15 changed files with 4105 additions and 2 deletions
@ -0,0 +1,284 @@ |
|||
<!-- 弹窗组件小龙开发所有 --> |
|||
<template> |
|||
<view> |
|||
<!-- 模态框 --> |
|||
<view @tap="Modal" :class="{ mask: model }"></view> |
|||
<!-- 弹窗主体 --> |
|||
<view |
|||
:style="{ height: barHidth + 'rpx' }" |
|||
class="active" |
|||
:class="{ add: model }" |
|||
> |
|||
<view class="title-model">{{ title }} <text @tap="close">x</text></view> |
|||
<view class="cont" :style="{ height: barHidth - 80 + 'rpx' }"> |
|||
<!-- 天 --> |
|||
<scroll-view class="day" :scroll-y="true"> |
|||
<view |
|||
:class="index === isIndex ? 'active_copy' : ''" |
|||
v-for="(item, index) in content" |
|||
:key="item.id" |
|||
@tap="dataCallback(index, item)" |
|||
>{{ item.timezh }}</view |
|||
> |
|||
</scroll-view> |
|||
|
|||
<!-- 时 --> |
|||
<scroll-view class="content-model" :scroll-y="true" :scroll-top="scrollTop"> |
|||
<view |
|||
class="appoint" |
|||
:class="index === Indexes ? 'longActive' : ''" |
|||
@tap="timeCallback(index, item)" |
|||
v-for="(item, index) in Days" |
|||
:key="index" |
|||
>{{ item.timestr |
|||
}}<text :class="index === Indexes ? 'cuIcon-check' : ''"></text |
|||
></view> |
|||
</scroll-view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
//弹窗组件标题 |
|||
title: { |
|||
type: String, |
|||
default: "请传入title", |
|||
}, |
|||
//弹窗组件数据 |
|||
content: { |
|||
type: Array, |
|||
// 默认测试数据 |
|||
default: () => [ |
|||
{ |
|||
timezh: "今天 (周三)", |
|||
timeformatter: "8-10", |
|||
id: 108, |
|||
timelist: [ |
|||
{ |
|||
timestr: "立即送达", |
|||
}, |
|||
{ |
|||
timestr: "15:35", |
|||
}, |
|||
{ |
|||
timestr: "16:05", |
|||
}, |
|||
], |
|||
}, |
|||
], |
|||
}, |
|||
//弹窗 窗口高度 |
|||
barHidth: { |
|||
type: Number, |
|||
default: 400, |
|||
}, |
|||
//点击模态框是否能关闭弹窗 |
|||
dodge: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
scrollTop: 0, |
|||
isIndex: 0, |
|||
Indexes: 0, |
|||
Days: [], |
|||
model: false, |
|||
}; |
|||
}, |
|||
|
|||
//初始化数据 |
|||
watch: { |
|||
content: { |
|||
immediate: true, |
|||
handler(newValue, oldValue) { |
|||
this.Days = this.content[0].timelist; |
|||
}, |
|||
}, |
|||
}, |
|||
|
|||
methods: { |
|||
// 关闭窗口 |
|||
close() { |
|||
this.model = false; |
|||
}, |
|||
|
|||
// 打开窗口 |
|||
open() { |
|||
this.model = true; |
|||
}, |
|||
|
|||
// 点击模态框关闭窗口 |
|||
Modal() { |
|||
if (this.dodge) { |
|||
this.close(); |
|||
} |
|||
}, |
|||
|
|||
//时间切换回顶 |
|||
gotop() { |
|||
this.scrollTop = 1; |
|||
this.$nextTick(function () { |
|||
this.scrollTop = 0; |
|||
}); |
|||
}, |
|||
|
|||
//切换日期 |
|||
dataCallback(inedx, item) { |
|||
this.isIndex = inedx; |
|||
this.Days = this.content[inedx].timelist; |
|||
this.Indexes = null; |
|||
this.gotop(); |
|||
this.$emit("dataCallback", item); |
|||
}, |
|||
|
|||
//选择时间 |
|||
timeCallback(inedx, item) { |
|||
this.Indexes = inedx; |
|||
this.modalName = null; |
|||
this.$emit("timeCallback", item); |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.mask { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: #000; |
|||
animation: getInto 0.5s 1; |
|||
opacity: 0.5; |
|||
z-index: 999; |
|||
} |
|||
|
|||
@keyframes getInto { |
|||
0% { |
|||
opacity: 0; |
|||
} |
|||
|
|||
100% { |
|||
opacity: 0.5; |
|||
} |
|||
} |
|||
|
|||
.active { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: 1000; |
|||
width: 100%; |
|||
height: 400rpx; |
|||
border-top-left-radius: 16rpx; |
|||
border-top-right-radius: 16rpx; |
|||
overflow: hidden; |
|||
transform: translateY(100%); |
|||
transition: 0.4s; |
|||
} |
|||
|
|||
.add { |
|||
transform: translateY(0); |
|||
} |
|||
|
|||
.title-model { |
|||
position: relative; |
|||
text-align: center; |
|||
background-color: #fff; |
|||
padding: 20rpx 0; |
|||
border-bottom: 2rpx solid #eee; |
|||
} |
|||
|
|||
.title-model > text { |
|||
position: absolute; |
|||
right: 14rpx; |
|||
width: 46rpx; |
|||
height: 46rpx; |
|||
line-height: 38rpx; |
|||
background-color: #ccc; |
|||
color: #fff; |
|||
border-radius: 50%; |
|||
} |
|||
|
|||
.cont { |
|||
display: flex; |
|||
background-color: #fff; |
|||
overflow-y: scroll; |
|||
} |
|||
|
|||
.day { |
|||
flex: 2; |
|||
background-color: #fff; |
|||
border-right: 2rpx solid #f8f8f8; |
|||
text-align: center; |
|||
border-bottom: 20px solid #fff; |
|||
} |
|||
|
|||
.day view { |
|||
padding: 30rpx 12rpx; |
|||
font-size: 28rpx; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.content-model { |
|||
flex: 4; |
|||
font-size: 28rpx; |
|||
border-bottom: 40rpx solid #fff; |
|||
background-color: #fff; |
|||
} |
|||
|
|||
.appoint { |
|||
text-align: left; |
|||
padding: 30rpx; |
|||
border-bottom: 2rpx solid #f8f8f8; |
|||
} |
|||
|
|||
.appoint text { |
|||
margin-left: 30rpx; |
|||
} |
|||
|
|||
.active_copy { |
|||
position: relative; |
|||
background-color: #d7f7e3; |
|||
color: #27c866; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.active_copy::after { |
|||
content: ""; |
|||
width: 5rpx; |
|||
height: 94rpx; |
|||
background: #27c866; |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
} |
|||
|
|||
.longActive { |
|||
position: relative; |
|||
color: #27c866; |
|||
} |
|||
|
|||
.cuIcon-check { |
|||
position: absolute; |
|||
width: 30rpx; |
|||
left: 210rpx; |
|||
height: 16rpx; |
|||
border-bottom: 4rpx solid #27c866; |
|||
border-left: 4rpx solid #27c866; |
|||
transform: rotate(-45deg); |
|||
} |
|||
|
|||
scroll-view ::-webkit-scrollbar { |
|||
display: none; |
|||
width: 0; |
|||
height: 0; |
|||
color: transparent; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,185 @@ |
|||
<template> |
|||
<view class="bs"> |
|||
<view class="bs-head"> |
|||
<view> |
|||
<text class="bs-kicker">ENERGY SHELF</text> |
|||
<text class="bs-title">BUFF 能量站</text> |
|||
</view> |
|||
<text class="bs-sub">当前 {{myTicket}} 券</text> |
|||
</view> |
|||
<scroll-view scroll-x class="bs-scroll" show-scrollbar="false"> |
|||
<view class="bs-row"> |
|||
<view class="bs-card" v-for="(b, i) in list" :key="i" :class="{active: b.active}" @tap="onBuy(b)"> |
|||
<view class="bs-card-emoji">{{buffEmoji(b.type)}}</view> |
|||
<view class="bs-card-name">{{b.name}}</view> |
|||
<view class="bs-card-desc">{{b.description}}</view> |
|||
<view class="bs-card-foot"> |
|||
<text class="bs-card-cost" v-if="!b.active">{{b.costTickets}} 券</text> |
|||
<text class="bs-card-cost active" v-else>生效中</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
myTicket: { |
|||
type: Number, |
|||
default: 0 |
|||
} |
|||
}, |
|||
methods: { |
|||
buffEmoji(type) { |
|||
const map = { |
|||
double: '2X', |
|||
shield: '盾', |
|||
lucky: 'LU', |
|||
hunt: '追', |
|||
stealth: '隐' |
|||
} |
|||
return map[type] || 'UP' |
|||
}, |
|||
onBuy(b) { |
|||
this.$emit('buy', b) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.bs { |
|||
margin-top: 34rpx; |
|||
} |
|||
|
|||
.bs-head { |
|||
display: flex; |
|||
align-items: flex-end; |
|||
justify-content: space-between; |
|||
margin-bottom: 18rpx; |
|||
} |
|||
|
|||
.bs-kicker { |
|||
display: block; |
|||
color: #59CBB5; |
|||
font-size: 18rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 3rpx; |
|||
margin-bottom: 4rpx; |
|||
} |
|||
|
|||
.bs-title { |
|||
display: block; |
|||
color: #12342F; |
|||
font-size: 36rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.bs-sub { |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.bs-scroll { |
|||
width: 100%; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.bs-row { |
|||
display: inline-flex; |
|||
padding-bottom: 12rpx; |
|||
} |
|||
|
|||
.bs-card { |
|||
display: inline-block; |
|||
width: 218rpx; |
|||
min-height: 240rpx; |
|||
margin-right: 20rpx; |
|||
padding: 24rpx; |
|||
border-radius: 36rpx; |
|||
background: linear-gradient(155deg, rgba(255,255,255,0.9), rgba(241,255,249,0.72)); |
|||
border: 2rpx solid rgba(255,255,255,0.9); |
|||
white-space: normal; |
|||
vertical-align: top; |
|||
box-shadow: 0 18rpx 42rpx rgba(53,214,166,0.09); |
|||
position: relative; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.bs-card:before { |
|||
content: ''; |
|||
position: absolute; |
|||
right: -36rpx; |
|||
top: -38rpx; |
|||
width: 130rpx; |
|||
height: 130rpx; |
|||
border-radius: 50%; |
|||
background: rgba(210,247,255,0.72); |
|||
} |
|||
|
|||
.bs-card.active { |
|||
border-color: rgba(53,214,166,0.45); |
|||
box-shadow: 0 20rpx 46rpx rgba(53,214,166,0.16); |
|||
} |
|||
|
|||
.bs-card-emoji { |
|||
position: relative; |
|||
width: 70rpx; |
|||
height: 70rpx; |
|||
line-height: 70rpx; |
|||
text-align: center; |
|||
border-radius: 24rpx; |
|||
background: linear-gradient(145deg, rgba(255,255,255,0.95), rgba(213,248,255,0.9)); |
|||
color: #22B889; |
|||
border: 2rpx solid rgba(255,255,255,0.95); |
|||
box-shadow: 0 12rpx 26rpx rgba(79,183,255,0.12); |
|||
font-size: 24rpx; |
|||
font-weight: 900; |
|||
font-family: DIN, Arial, sans-serif; |
|||
} |
|||
|
|||
.bs-card-name { |
|||
position: relative; |
|||
margin-top: 14rpx; |
|||
color: #12342F; |
|||
font-size: 28rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.bs-card-desc { |
|||
position: relative; |
|||
margin-top: 8rpx; |
|||
color: #7E9691; |
|||
font-size: 20rpx; |
|||
min-height: 56rpx; |
|||
line-height: 28rpx; |
|||
} |
|||
|
|||
.bs-card-foot { |
|||
position: relative; |
|||
margin-top: 14rpx; |
|||
} |
|||
|
|||
.bs-card-cost { |
|||
display: inline-block; |
|||
padding: 8rpx 20rpx; |
|||
border-radius: 999rpx; |
|||
background: linear-gradient(135deg, #DFFBF1, #E8F6FF); |
|||
color: #22B889; |
|||
border: 1rpx solid rgba(255,255,255,0.95); |
|||
font-size: 22rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.bs-card-cost.active { |
|||
background: rgba(53,214,166,0.12); |
|||
color: #22B889; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,291 @@ |
|||
<template> |
|||
<view v-if="show" class="hm-mask"> |
|||
<view class="hm"> |
|||
<!-- 追击动画区 --> |
|||
<view class="hm-stage" v-if="phase !== 'result'"> |
|||
<view class="hm-radar"> |
|||
<view class="hm-radar-sweep"></view> |
|||
<view class="hm-radar-ring r1"></view> |
|||
<view class="hm-radar-ring r2"></view> |
|||
<view class="hm-rocket" :class="phase">GO</view> |
|||
<image class="hm-target-avatar" :src="target.avatar || defaultAvatar" mode="aspectFill"></image> |
|||
</view> |
|||
<view class="hm-phase-text">{{phaseText}}</view> |
|||
<view class="hm-dots"> |
|||
<text class="hm-dot"></text> |
|||
<text class="hm-dot"></text> |
|||
<text class="hm-dot"></text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 结果区 --> |
|||
<view class="hm-result" v-else> |
|||
<view class="hm-result-emoji">{{resultBadge}}</view> |
|||
<view class="hm-result-title" :class="result.result">{{resultTitle}}</view> |
|||
<view class="hm-result-msg">{{result.message}}</view> |
|||
<view class="hm-result-gain" v-if="result.result === 'success'"> |
|||
<text class="hm-gain-num">+{{result.totalGain}}</text> |
|||
<text class="hm-gain-unit">星球券</text> |
|||
</view> |
|||
<view class="hm-result-remain">今日剩余追捕 {{result.remainHunt}} 次</view> |
|||
<view class="hm-result-btn" @tap="onClose">{{result.result === 'success' ? '收入囊中' : '知道了'}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
show: { type: Boolean, default: false }, |
|||
phase: { type: String, default: 'searching' }, |
|||
result: { type: Object, default: null }, |
|||
target: { type: Object, default: () => ({}) } |
|||
}, |
|||
data() { |
|||
return { |
|||
defaultAvatar: 'https://jewel-shop.oss-cn-beijing.aliyuncs.com/41cfb56caff4419b94b69d0f2303b602.png' |
|||
} |
|||
}, |
|||
computed: { |
|||
phaseText() { |
|||
const map = { |
|||
searching: '雷达搜索目标飞船...', |
|||
locking: '已锁定目标坐标...', |
|||
chasing: '星际追击中...' |
|||
} |
|||
return map[this.phase] || '追击中...' |
|||
}, |
|||
resultBadge() { |
|||
if (!this.result) return 'GO' |
|||
if (this.result.result === 'success') return 'GET' |
|||
if (this.result.result === 'shield') return 'SAFE' |
|||
return 'MISS' |
|||
}, |
|||
resultTitle() { |
|||
if (!this.result) return '' |
|||
if (this.result.result === 'success') return '追捕成功' |
|||
if (this.result.result === 'shield') return '目标已防护' |
|||
return '追捕扑空' |
|||
} |
|||
}, |
|||
methods: { |
|||
onClose() { |
|||
this.$emit('close') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.hm-mask { |
|||
position: fixed; |
|||
top: 0; left: 0; right: 0; bottom: 0; |
|||
background: rgba(18,52,47,0.28); |
|||
backdrop-filter: blur(8px); |
|||
z-index: 80; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.hm { |
|||
width: 580rpx; |
|||
padding: 56rpx 40rpx 40rpx; |
|||
border-radius: 46rpx; |
|||
background: linear-gradient(155deg, rgba(255,255,255,0.94), rgba(244,255,249,0.78)); |
|||
border: 2rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 34rpx 80rpx rgba(53,214,166,0.22); |
|||
} |
|||
|
|||
.hm-stage { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
} |
|||
|
|||
.hm-radar { |
|||
position: relative; |
|||
width: 340rpx; |
|||
height: 340rpx; |
|||
border-radius: 50%; |
|||
background: radial-gradient(circle, rgba(53,214,166,0.14), rgba(79,183,255,0.06) 52%, transparent 70%); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.hm-radar-ring { |
|||
position: absolute; |
|||
border-radius: 50%; |
|||
border: 2rpx solid rgba(53,214,166,0.26); |
|||
} |
|||
|
|||
.hm-radar-ring.r1 { width: 240rpx; height: 240rpx; } |
|||
.hm-radar-ring.r2 { width: 340rpx; height: 340rpx; } |
|||
|
|||
.hm-radar-sweep { |
|||
position: absolute; |
|||
width: 154rpx; |
|||
height: 5rpx; |
|||
top: 50%; |
|||
left: 50%; |
|||
transform-origin: left center; |
|||
background: linear-gradient(90deg, rgba(53,214,166,0.68), rgba(53,214,166,0)); |
|||
border-radius: 999rpx; |
|||
animation: sweep 1.6s linear infinite; |
|||
} |
|||
|
|||
@keyframes sweep { |
|||
from { transform: rotate(0deg); } |
|||
to { transform: rotate(360deg); } |
|||
} |
|||
|
|||
.hm-target-avatar { |
|||
width: 96rpx; |
|||
height: 96rpx; |
|||
border-radius: 50%; |
|||
border: 5rpx solid rgba(255,255,255,0.94); |
|||
opacity: 0.95; |
|||
box-shadow: 0 14rpx 30rpx rgba(255,122,89,0.18); |
|||
} |
|||
|
|||
.hm-rocket { |
|||
position: absolute; |
|||
width: 58rpx; |
|||
height: 58rpx; |
|||
line-height: 58rpx; |
|||
text-align: center; |
|||
border-radius: 50%; |
|||
background: linear-gradient(135deg, #FF7A59, #FFB84D); |
|||
color: #FFFFFF; |
|||
font-size: 20rpx; |
|||
font-weight: 900; |
|||
left: 20rpx; |
|||
top: 130rpx; |
|||
box-shadow: 0 12rpx 26rpx rgba(255,122,89,0.24); |
|||
} |
|||
|
|||
.hm-rocket.searching { animation: orbit 2.5s linear infinite; } |
|||
.hm-rocket.locking { animation: orbit 1.4s linear infinite; } |
|||
.hm-rocket.chasing { animation: orbit 0.7s linear infinite; } |
|||
|
|||
@keyframes orbit { |
|||
0% { transform: rotate(0deg) translateX(150rpx) rotate(0deg); } |
|||
100% { transform: rotate(360deg) translateX(150rpx) rotate(-360deg); } |
|||
} |
|||
|
|||
.hm-phase-text { |
|||
margin-top: 30rpx; |
|||
color: #12342F; |
|||
font-size: 28rpx; |
|||
font-weight: 800; |
|||
letter-spacing: 1rpx; |
|||
} |
|||
|
|||
.hm-dots { |
|||
margin-top: 16rpx; |
|||
display: flex; |
|||
} |
|||
|
|||
.hm-dot { |
|||
width: 12rpx; |
|||
height: 12rpx; |
|||
border-radius: 50%; |
|||
background: #35D6A6; |
|||
margin: 0 6rpx; |
|||
animation: blink 1.2s ease infinite; |
|||
} |
|||
|
|||
.hm-dot:nth-child(2) { animation-delay: 0.2s; } |
|||
.hm-dot:nth-child(3) { animation-delay: 0.4s; } |
|||
|
|||
@keyframes blink { |
|||
0%, 100% { opacity: 0.3; } |
|||
50% { opacity: 1; } |
|||
} |
|||
|
|||
.hm-result { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
} |
|||
|
|||
.hm-result-emoji { |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
line-height: 160rpx; |
|||
text-align: center; |
|||
border-radius: 50%; |
|||
background: linear-gradient(145deg, #E5FFF1, #EAF8FF); |
|||
color: #22B889; |
|||
font-size: 30rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 2rpx; |
|||
animation: pop 0.5s ease; |
|||
box-shadow: inset 0 0 0 2rpx rgba(255,255,255,0.92), 0 18rpx 42rpx rgba(53,214,166,0.14); |
|||
} |
|||
|
|||
@keyframes pop { |
|||
0% { transform: scale(0.3); opacity: 0; } |
|||
70% { transform: scale(1.2); } |
|||
100% { transform: scale(1); opacity: 1; } |
|||
} |
|||
|
|||
.hm-result-title { |
|||
margin-top: 16rpx; |
|||
font-size: 40rpx; |
|||
font-weight: 800; |
|||
color: #12342F; |
|||
} |
|||
|
|||
.hm-result-title.success { color: #22B889; } |
|||
.hm-result-title.shield { color: #4FB7FF; } |
|||
.hm-result-title.fail { color: #7E9691; } |
|||
|
|||
.hm-result-msg { |
|||
margin-top: 14rpx; |
|||
color: #42635E; |
|||
font-size: 26rpx; |
|||
text-align: center; |
|||
padding: 0 20rpx; |
|||
} |
|||
|
|||
.hm-result-gain { |
|||
margin-top: 24rpx; |
|||
display: flex; |
|||
align-items: baseline; |
|||
} |
|||
|
|||
.hm-gain-num { |
|||
color: #22B889; |
|||
font-size: 64rpx; |
|||
font-weight: 800; |
|||
} |
|||
|
|||
.hm-gain-unit { |
|||
color: #42635E; |
|||
font-size: 26rpx; |
|||
margin-left: 8rpx; |
|||
} |
|||
|
|||
.hm-result-remain { |
|||
margin-top: 16rpx; |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
} |
|||
|
|||
.hm-result-btn { |
|||
margin-top: 36rpx; |
|||
width: 100%; |
|||
height: 84rpx; |
|||
line-height: 84rpx; |
|||
text-align: center; |
|||
border-radius: 42rpx; |
|||
background: linear-gradient(135deg, #35D6A6, #4FB7FF); |
|||
color: #FFFFFF; |
|||
font-size: 30rpx; |
|||
font-weight: 800; |
|||
box-shadow: 0 18rpx 36rpx rgba(53,214,166,0.22); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,179 @@ |
|||
<template> |
|||
<view class="pb" @tap="onOpen"> |
|||
<view class="pb-tag">{{available ? 'TODAY DROP' : 'TOMORROW DROP'}}</view> |
|||
<view class="pb-visual"> |
|||
<view class="pb-glow" v-if="available"></view> |
|||
<view class="pb-box" :class="{shaking: opening, dim: !available}"> |
|||
<view class="pb-box-lid"></view> |
|||
<view class="pb-box-face">?</view> |
|||
</view> |
|||
</view> |
|||
<view class="pb-mid"> |
|||
<view class="pb-title">幸运盲盒舱</view> |
|||
<view class="pb-desc">{{available ? '今日补给已抵达,拆开看看有什么' : '今日已拆盒,明天再来补给'}}</view> |
|||
</view> |
|||
<view class="pb-btn" :class="{disabled: !available}"> |
|||
{{opening ? '拆盒中' : (available ? '拆盲盒' : '已拆')}} |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
available: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
opening: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
methods: { |
|||
onOpen() { |
|||
if (!this.available || this.opening) return |
|||
this.$emit('open') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.pb { |
|||
margin-top: 28rpx; |
|||
padding: 34rpx 28rpx; |
|||
border-radius: 46rpx 30rpx 46rpx 30rpx; |
|||
background: |
|||
radial-gradient(circle at 16% 18%, rgba(255,255,255,0.86), transparent 22%), |
|||
linear-gradient(135deg, rgba(255,255,255,0.86), rgba(255,246,219,0.78) 52%, rgba(232,223,255,0.72)); |
|||
border: 2rpx solid rgba(255,255,255,0.9); |
|||
display: flex; |
|||
align-items: center; |
|||
position: relative; |
|||
overflow: hidden; |
|||
box-shadow: 0 22rpx 54rpx rgba(255,184,77,0.15); |
|||
} |
|||
|
|||
.pb-tag { |
|||
position: absolute; |
|||
right: 24rpx; |
|||
top: 18rpx; |
|||
color: rgba(255,122,89,0.52); |
|||
font-size: 18rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 2rpx; |
|||
} |
|||
|
|||
.pb-visual { |
|||
position: relative; |
|||
width: 126rpx; |
|||
height: 126rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.pb-glow { |
|||
position: absolute; |
|||
width: 150rpx; |
|||
height: 150rpx; |
|||
border-radius: 50%; |
|||
background: radial-gradient(circle, rgba(255,184,77,0.38), transparent 66%); |
|||
animation: spark 2s ease-in-out infinite; |
|||
} |
|||
|
|||
.pb-box { |
|||
position: relative; |
|||
width: 90rpx; |
|||
height: 92rpx; |
|||
border-radius: 22rpx; |
|||
background: linear-gradient(145deg, #FF8B6A, #FFCF7A); |
|||
box-shadow: inset -10rpx -12rpx 22rpx rgba(146,75,26,0.18), 0 16rpx 34rpx rgba(255,122,89,0.26); |
|||
} |
|||
|
|||
.pb-box.shaking { |
|||
animation: shake 0.3s ease-in-out infinite; |
|||
} |
|||
|
|||
.pb-box.dim { |
|||
filter: grayscale(0.8); |
|||
opacity: 0.58; |
|||
} |
|||
|
|||
.pb-box-lid { |
|||
position: absolute; |
|||
left: -8rpx; |
|||
top: -18rpx; |
|||
width: 106rpx; |
|||
height: 34rpx; |
|||
border-radius: 18rpx; |
|||
background: linear-gradient(135deg, #FFFFFF, #FFD38C); |
|||
transform: rotate(-5deg); |
|||
} |
|||
|
|||
.pb-box-face { |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 54%; |
|||
transform: translate(-50%, -50%); |
|||
width: 42rpx; |
|||
height: 42rpx; |
|||
line-height: 42rpx; |
|||
text-align: center; |
|||
border-radius: 50%; |
|||
background: rgba(255,255,255,0.86); |
|||
color: #FF7A59; |
|||
font-size: 28rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
@keyframes shake { |
|||
0%, 100% { transform: rotate(-6deg) scale(1); } |
|||
50% { transform: rotate(7deg) scale(1.04); } |
|||
} |
|||
|
|||
@keyframes spark { |
|||
0%, 100% { opacity: 0.42; transform: scale(0.86); } |
|||
50% { opacity: 0.95; transform: scale(1.1); } |
|||
} |
|||
|
|||
.pb-mid { |
|||
flex: 1; |
|||
margin-left: 18rpx; |
|||
min-width: 0; |
|||
} |
|||
|
|||
.pb-title { |
|||
color: #12342F; |
|||
font-size: 32rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.pb-desc { |
|||
color: #42635E; |
|||
font-size: 23rpx; |
|||
margin-top: 8rpx; |
|||
line-height: 34rpx; |
|||
} |
|||
|
|||
.pb-btn { |
|||
padding: 0 24rpx; |
|||
height: 62rpx; |
|||
line-height: 62rpx; |
|||
border-radius: 999rpx; |
|||
background: linear-gradient(135deg, #FFB84D, #FF7A59); |
|||
color: #FFFFFF; |
|||
font-size: 25rpx; |
|||
font-weight: 800; |
|||
box-shadow: 0 14rpx 28rpx rgba(255,122,89,0.24); |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.pb-btn.disabled { |
|||
background: rgba(18,52,47,0.08); |
|||
color: #7E9691; |
|||
box-shadow: none; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,690 @@ |
|||
<template> |
|||
<view class="ph"> |
|||
<view class="ph-story"> |
|||
<text class="ph-kicker">BANJINLI ORBIT</text> |
|||
<text class="ph-title">今天,登陆白嫖星球</text> |
|||
<text class="ph-sub">攒券、追捕、开盲盒,全校一起瓜分补给池</text> |
|||
</view> |
|||
|
|||
<view class="ph-meteor ph-meteor-a"></view> |
|||
<view class="ph-meteor ph-meteor-b"></view> |
|||
<view class="ph-station"> |
|||
<view class="ph-station-core"></view> |
|||
<view class="ph-station-wing ph-station-wing-left"></view> |
|||
<view class="ph-station-wing ph-station-wing-right"></view> |
|||
</view> |
|||
<view class="ph-asteroid ph-asteroid-a"></view> |
|||
<view class="ph-asteroid ph-asteroid-b"></view> |
|||
<view class="ph-floating-box"> |
|||
<view class="ph-floating-box-lid"></view> |
|||
<text>?</text> |
|||
</view> |
|||
|
|||
<view class="ph-orbit ph-orbit-a"></view> |
|||
<view class="ph-orbit ph-orbit-b"></view> |
|||
<view class="ph-orbit ph-orbit-c"></view> |
|||
|
|||
<view class="ph-planet-wrap"> |
|||
<view class="ph-planet-glow"></view> |
|||
<view class="ph-planet"> |
|||
<view class="ph-planet-map ph-planet-map-a"></view> |
|||
<view class="ph-planet-map ph-planet-map-b"></view> |
|||
<view class="ph-planet-map ph-planet-map-c"></view> |
|||
<view class="ph-shine ph-shine-a"></view> |
|||
<view class="ph-shine ph-shine-b"></view> |
|||
<view class="ph-atmosphere"></view> |
|||
</view> |
|||
<view class="ph-planet-core"> |
|||
<view class="ph-core-label">今日补给池</view> |
|||
<view class="ph-pool"> |
|||
<text class="ph-pool-symbol">¥</text> |
|||
<text class="ph-pool-num">{{poolText}}</text> |
|||
</view> |
|||
<view class="ph-pool-label">星球券越多,瓜分权重越高</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="ph-squirrel"> |
|||
<image class="ph-squirrel-img" src="/static/images/img/loading.gif" mode="aspectFit"></image> |
|||
<view class="ph-squirrel-tag">IP</view> |
|||
</view> |
|||
|
|||
<view class="ph-satellite ph-satellite-left"> |
|||
<text class="ph-satellite-num">{{data.joinCount || 0}}</text> |
|||
<text class="ph-satellite-label">全校登陆</text> |
|||
</view> |
|||
<view class="ph-satellite ph-satellite-right"> |
|||
<text class="ph-satellite-num">{{rankText}}</text> |
|||
<text class="ph-satellite-label">财富坐标</text> |
|||
</view> |
|||
<view class="ph-ticket-pill">我的星球券 {{data.myTicketCount || 0}} 张</view> |
|||
|
|||
<view class="ph-count"> |
|||
<view class="ph-period">第 {{data.periodNo || '--'}} 期</view> |
|||
<view class="ph-count-unit"> |
|||
<text>{{cd.h}}</text> |
|||
<text>H</text> |
|||
</view> |
|||
<view class="ph-count-unit"> |
|||
<text>{{cd.m}}</text> |
|||
<text>M</text> |
|||
</view> |
|||
<view class="ph-count-unit"> |
|||
<text>{{cd.s}}</text> |
|||
<text>S</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
data: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
remain: 0, |
|||
timer: null |
|||
} |
|||
}, |
|||
computed: { |
|||
poolText() { |
|||
const v = Number(this.data.poolAmount || 0) |
|||
return v.toFixed(2) |
|||
}, |
|||
rankText() { |
|||
const r = this.data.myRankNo || 0 |
|||
return r > 0 ? ('No.' + r) : '未上榜' |
|||
}, |
|||
cd() { |
|||
let s = Math.floor(this.remain / 1000) |
|||
const h = Math.floor(s / 3600) |
|||
s -= h * 3600 |
|||
const m = Math.floor(s / 60) |
|||
s -= m * 60 |
|||
return { |
|||
h: this.pad(h), |
|||
m: this.pad(m), |
|||
s: this.pad(s) |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
'data.countdownMillis'(val) { |
|||
this.remain = val || 0 |
|||
this.startTimer() |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.remain = this.data.countdownMillis || 0 |
|||
this.startTimer() |
|||
}, |
|||
beforeDestroy() { |
|||
if (this.timer) clearInterval(this.timer) |
|||
}, |
|||
methods: { |
|||
pad(n) { |
|||
return n < 10 ? ('0' + n) : ('' + n) |
|||
}, |
|||
startTimer() { |
|||
if (this.timer) clearInterval(this.timer) |
|||
this.timer = setInterval(() => { |
|||
if (this.remain <= 1000) { |
|||
this.remain = 0 |
|||
clearInterval(this.timer) |
|||
return |
|||
} |
|||
this.remain -= 1000 |
|||
}, 1000) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.ph { |
|||
position: relative; |
|||
margin-top: 6rpx; |
|||
height: 820rpx; |
|||
overflow: visible; |
|||
} |
|||
|
|||
.ph-story { |
|||
position: absolute; |
|||
left: 8rpx; |
|||
top: 12rpx; |
|||
z-index: 6; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.ph-kicker { |
|||
color: #35D6A6; |
|||
font-size: 18rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 4rpx; |
|||
} |
|||
|
|||
.ph-title { |
|||
margin-top: 10rpx; |
|||
color: #12342F; |
|||
font-size: 44rpx; |
|||
font-weight: 900; |
|||
letter-spacing: -1rpx; |
|||
} |
|||
|
|||
.ph-sub { |
|||
margin-top: 10rpx; |
|||
color: #42635E; |
|||
font-size: 24rpx; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.ph-meteor { |
|||
position: absolute; |
|||
width: 180rpx; |
|||
height: 3rpx; |
|||
border-radius: 999rpx; |
|||
background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,0.95), rgba(79,183,255,0.4)); |
|||
transform: rotate(-28deg); |
|||
animation: meteorFly 4.8s linear infinite; |
|||
z-index: 2; |
|||
} |
|||
|
|||
.ph-meteor-a { |
|||
top: 132rpx; |
|||
right: -120rpx; |
|||
} |
|||
|
|||
.ph-meteor-b { |
|||
top: 370rpx; |
|||
left: 40rpx; |
|||
width: 120rpx; |
|||
animation-delay: -2.2s; |
|||
opacity: 0.72; |
|||
} |
|||
|
|||
@keyframes meteorFly { |
|||
0% { transform: translate3d(180rpx, -70rpx, 0) rotate(-28deg); opacity: 0; } |
|||
12% { opacity: 1; } |
|||
70% { opacity: 1; } |
|||
100% { transform: translate3d(-760rpx, 260rpx, 0) rotate(-28deg); opacity: 0; } |
|||
} |
|||
|
|||
.ph-station { |
|||
position: absolute; |
|||
right: 26rpx; |
|||
top: 150rpx; |
|||
width: 170rpx; |
|||
height: 78rpx; |
|||
z-index: 4; |
|||
animation: stationFloat 5.6s ease-in-out infinite; |
|||
} |
|||
|
|||
@keyframes stationFloat { |
|||
0%, 100% { transform: translateY(0) rotate(4deg); } |
|||
50% { transform: translateY(-16rpx) rotate(-2deg); } |
|||
} |
|||
|
|||
.ph-station-core { |
|||
position: absolute; |
|||
left: 58rpx; |
|||
top: 20rpx; |
|||
width: 56rpx; |
|||
height: 38rpx; |
|||
border-radius: 18rpx; |
|||
background: linear-gradient(145deg, rgba(255,255,255,0.96), rgba(224,247,255,0.88)); |
|||
border: 2rpx solid rgba(79,183,255,0.28); |
|||
box-shadow: 0 14rpx 28rpx rgba(79,183,255,0.18); |
|||
} |
|||
|
|||
.ph-station-wing { |
|||
position: absolute; |
|||
top: 30rpx; |
|||
width: 58rpx; |
|||
height: 18rpx; |
|||
border-radius: 999rpx; |
|||
background: linear-gradient(90deg, rgba(143,124,255,0.76), rgba(79,183,255,0.72)); |
|||
} |
|||
|
|||
.ph-station-wing-left { left: 0; } |
|||
.ph-station-wing-right { right: 0; } |
|||
|
|||
.ph-asteroid { |
|||
position: absolute; |
|||
border-radius: 46% 54% 44% 56%; |
|||
background: linear-gradient(145deg, #FFE6A6, #FFB7D1); |
|||
box-shadow: inset -10rpx -10rpx 20rpx rgba(150,93,48,0.12), 0 12rpx 30rpx rgba(255,184,77,0.18); |
|||
z-index: 3; |
|||
animation: asteroidFloat 6.2s ease-in-out infinite; |
|||
} |
|||
|
|||
.ph-asteroid-a { |
|||
left: 18rpx; |
|||
top: 260rpx; |
|||
width: 62rpx; |
|||
height: 48rpx; |
|||
} |
|||
|
|||
.ph-asteroid-b { |
|||
right: 86rpx; |
|||
top: 514rpx; |
|||
width: 42rpx; |
|||
height: 34rpx; |
|||
animation-delay: -2s; |
|||
} |
|||
|
|||
@keyframes asteroidFloat { |
|||
0%, 100% { transform: translateY(0) rotate(0deg); } |
|||
50% { transform: translateY(18rpx) rotate(12deg); } |
|||
} |
|||
|
|||
.ph-floating-box { |
|||
position: absolute; |
|||
left: 34rpx; |
|||
top: 525rpx; |
|||
width: 88rpx; |
|||
height: 86rpx; |
|||
border-radius: 22rpx; |
|||
background: linear-gradient(145deg, #FF8B6A, #FFCF7A); |
|||
box-shadow: inset -8rpx -10rpx 18rpx rgba(146,75,26,0.18), 0 18rpx 36rpx rgba(255,122,89,0.22); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
color: #FFFFFF; |
|||
font-size: 32rpx; |
|||
font-weight: 900; |
|||
z-index: 5; |
|||
animation: treasureFloat 4.4s ease-in-out infinite; |
|||
} |
|||
|
|||
.ph-floating-box-lid { |
|||
position: absolute; |
|||
left: -7rpx; |
|||
top: -16rpx; |
|||
width: 102rpx; |
|||
height: 32rpx; |
|||
border-radius: 18rpx; |
|||
background: linear-gradient(135deg, #FFFFFF, #FFD38C); |
|||
transform: rotate(-5deg); |
|||
} |
|||
|
|||
@keyframes treasureFloat { |
|||
0%, 100% { transform: translateY(0) rotate(-7deg); } |
|||
50% { transform: translateY(-18rpx) rotate(5deg); } |
|||
} |
|||
|
|||
.ph-orbit { |
|||
position: absolute; |
|||
left: 50%; |
|||
border: 2rpx solid rgba(255,255,255,0.72); |
|||
border-radius: 50%; |
|||
transform: translateX(-50%) rotate(-16deg); |
|||
z-index: 2; |
|||
} |
|||
|
|||
.ph-orbit-a { |
|||
top: 196rpx; |
|||
width: 720rpx; |
|||
height: 330rpx; |
|||
opacity: 0.76; |
|||
} |
|||
|
|||
.ph-orbit-b { |
|||
top: 250rpx; |
|||
width: 610rpx; |
|||
height: 260rpx; |
|||
opacity: 0.46; |
|||
} |
|||
|
|||
.ph-orbit-c { |
|||
top: 312rpx; |
|||
width: 760rpx; |
|||
height: 220rpx; |
|||
opacity: 0.36; |
|||
transform: translateX(-50%) rotate(12deg); |
|||
} |
|||
|
|||
.ph-planet-wrap { |
|||
position: absolute; |
|||
top: 142rpx; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
width: 610rpx; |
|||
height: 610rpx; |
|||
z-index: 3; |
|||
animation: planetBreath 4.4s ease-in-out infinite; |
|||
} |
|||
|
|||
.ph-planet-glow { |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 50%; |
|||
width: 680rpx; |
|||
height: 680rpx; |
|||
border-radius: 50%; |
|||
transform: translate(-50%, -50%); |
|||
background: radial-gradient(circle, rgba(53,214,166,0.26), rgba(79,183,255,0.12) 42%, rgba(255,255,255,0) 68%); |
|||
filter: blur(8rpx); |
|||
} |
|||
|
|||
.ph-planet { |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 50%; |
|||
transform: translate(-50%, -50%); |
|||
width: 570rpx; |
|||
height: 570rpx; |
|||
border-radius: 50%; |
|||
background: |
|||
radial-gradient(circle at 28% 22%, rgba(255,255,255,0.96) 0%, rgba(255,255,255,0.72) 15%, transparent 28%), |
|||
radial-gradient(circle at 72% 74%, rgba(143,124,255,0.34), transparent 38%), |
|||
linear-gradient(145deg, rgba(201,255,225,0.82) 0%, rgba(166,242,255,0.78) 46%, rgba(232,223,255,0.82) 100%); |
|||
box-shadow: |
|||
inset -54rpx -66rpx 90rpx rgba(18,52,47,0.12), |
|||
inset 36rpx 42rpx 78rpx rgba(255,255,255,0.68), |
|||
0 42rpx 96rpx rgba(53,214,166,0.28); |
|||
border: 2rpx solid rgba(255,255,255,0.72); |
|||
overflow: hidden; |
|||
} |
|||
|
|||
@keyframes planetBreath { |
|||
0%, 100% { transform: translateX(-50%) translateY(0) scale(1); } |
|||
50% { transform: translateX(-50%) translateY(-14rpx) scale(1.02); } |
|||
} |
|||
|
|||
.ph-planet-map { |
|||
position: absolute; |
|||
background: rgba(53,214,166,0.16); |
|||
filter: blur(1rpx); |
|||
} |
|||
|
|||
.ph-planet-map-a { |
|||
left: 96rpx; |
|||
top: 172rpx; |
|||
width: 172rpx; |
|||
height: 82rpx; |
|||
border-radius: 56% 44% 60% 40%; |
|||
transform: rotate(-16deg); |
|||
} |
|||
|
|||
.ph-planet-map-b { |
|||
right: 96rpx; |
|||
top: 298rpx; |
|||
width: 188rpx; |
|||
height: 92rpx; |
|||
border-radius: 44% 56% 42% 58%; |
|||
background: rgba(79,183,255,0.14); |
|||
transform: rotate(20deg); |
|||
} |
|||
|
|||
.ph-planet-map-c { |
|||
left: 214rpx; |
|||
bottom: 92rpx; |
|||
width: 138rpx; |
|||
height: 62rpx; |
|||
border-radius: 50%; |
|||
background: rgba(143,124,255,0.12); |
|||
} |
|||
|
|||
.ph-shine { |
|||
position: absolute; |
|||
border-radius: 50%; |
|||
background: rgba(255,255,255,0.72); |
|||
filter: blur(2rpx); |
|||
} |
|||
|
|||
.ph-shine-a { |
|||
left: 94rpx; |
|||
top: 80rpx; |
|||
width: 140rpx; |
|||
height: 74rpx; |
|||
transform: rotate(-22deg); |
|||
} |
|||
|
|||
.ph-shine-b { |
|||
right: 96rpx; |
|||
top: 98rpx; |
|||
width: 66rpx; |
|||
height: 34rpx; |
|||
opacity: 0.58; |
|||
} |
|||
|
|||
.ph-atmosphere { |
|||
position: absolute; |
|||
left: 28rpx; |
|||
right: 28rpx; |
|||
top: 38rpx; |
|||
height: 150rpx; |
|||
border-top: 3rpx solid rgba(255,255,255,0.5); |
|||
border-radius: 50%; |
|||
transform: rotate(-12deg); |
|||
} |
|||
|
|||
.ph-planet-core { |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 50%; |
|||
transform: translate(-50%, -50%); |
|||
width: 390rpx; |
|||
min-height: 220rpx; |
|||
border-radius: 56rpx; |
|||
background: rgba(255,255,255,0.34); |
|||
border: 1rpx solid rgba(255,255,255,0.72); |
|||
backdrop-filter: blur(14px); |
|||
box-shadow: inset 0 0 0 1rpx rgba(255,255,255,0.36), 0 18rpx 44rpx rgba(53,214,166,0.12); |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
z-index: 5; |
|||
} |
|||
|
|||
.ph-core-label { |
|||
color: #42635E; |
|||
font-size: 24rpx; |
|||
font-weight: 800; |
|||
letter-spacing: 2rpx; |
|||
} |
|||
|
|||
.ph-period { |
|||
position: relative; |
|||
text-align: center; |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
font-weight: 700; |
|||
margin-right: 12rpx; |
|||
} |
|||
|
|||
.ph-pool { |
|||
position: relative; |
|||
text-align: center; |
|||
margin-top: 8rpx; |
|||
color: #16A779; |
|||
} |
|||
|
|||
.ph-pool-symbol { |
|||
font-size: 38rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.ph-pool-num { |
|||
font-size: 92rpx; |
|||
font-weight: 900; |
|||
font-family: DIN, sans-serif; |
|||
letter-spacing: -2rpx; |
|||
} |
|||
|
|||
.ph-pool-label { |
|||
position: relative; |
|||
text-align: center; |
|||
color: #42635E; |
|||
font-size: 24rpx; |
|||
margin-top: 2rpx; |
|||
} |
|||
|
|||
.ph-ticket-pill { |
|||
position: absolute; |
|||
left: 30rpx; |
|||
bottom: 86rpx; |
|||
z-index: 6; |
|||
padding: 12rpx 22rpx; |
|||
border-radius: 999rpx; |
|||
background: rgba(18,52,47,0.86); |
|||
border: 1rpx solid rgba(255,255,255,0.9); |
|||
color: #FFFFFF; |
|||
font-size: 23rpx; |
|||
font-weight: 900; |
|||
box-shadow: 0 16rpx 34rpx rgba(18,52,47,0.18); |
|||
} |
|||
|
|||
.ph-count { |
|||
position: absolute; |
|||
left: 50%; |
|||
bottom: 18rpx; |
|||
transform: translateX(-50%); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 12rpx 16rpx; |
|||
border-radius: 999rpx; |
|||
background: rgba(255,255,255,0.72); |
|||
border: 1rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 18rpx 42rpx rgba(79,183,255,0.14); |
|||
backdrop-filter: blur(8px); |
|||
z-index: 6; |
|||
} |
|||
|
|||
.ph-count-label { |
|||
color: #42635E; |
|||
font-size: 24rpx; |
|||
font-weight: 700; |
|||
margin-right: 12rpx; |
|||
} |
|||
|
|||
.ph-count-unit { |
|||
width: 64rpx; |
|||
height: 64rpx; |
|||
margin-left: 8rpx; |
|||
border-radius: 22rpx; |
|||
background: linear-gradient(145deg, #F8FFFB, #E1F8FF); |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
box-shadow: inset 0 0 0 1rpx rgba(255,255,255,0.72); |
|||
} |
|||
|
|||
.ph-count-unit text:first-child { |
|||
color: #12342F; |
|||
font-size: 28rpx; |
|||
font-weight: 900; |
|||
line-height: 30rpx; |
|||
font-family: DIN, Arial, sans-serif; |
|||
} |
|||
|
|||
.ph-count-unit text:last-child { |
|||
color: #7E9691; |
|||
font-size: 16rpx; |
|||
font-weight: 700; |
|||
line-height: 20rpx; |
|||
} |
|||
|
|||
.ph-satellite { |
|||
position: absolute; |
|||
z-index: 6; |
|||
min-width: 132rpx; |
|||
padding: 14rpx 18rpx; |
|||
border-radius: 28rpx; |
|||
background: rgba(255,255,255,0.74); |
|||
border: 1rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 18rpx 38rpx rgba(53,214,166,0.12); |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
animation: orbitFloat 4s ease-in-out infinite; |
|||
} |
|||
|
|||
.ph-satellite-left { |
|||
left: 0; |
|||
top: 350rpx; |
|||
transform: rotate(-6deg); |
|||
} |
|||
|
|||
.ph-satellite-right { |
|||
right: 0; |
|||
top: 428rpx; |
|||
transform: rotate(7deg); |
|||
animation-delay: -1.5s; |
|||
} |
|||
|
|||
@keyframes orbitFloat { |
|||
0%, 100% { margin-top: 0; } |
|||
50% { margin-top: -12rpx; } |
|||
} |
|||
|
|||
.ph-satellite-num { |
|||
color: #12342F; |
|||
font-size: 30rpx; |
|||
font-weight: 900; |
|||
max-width: 150rpx; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.ph-satellite-label { |
|||
margin-top: 2rpx; |
|||
color: #7E9691; |
|||
font-size: 20rpx; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.ph-squirrel { |
|||
position: absolute; |
|||
right: 18rpx; |
|||
top: 585rpx; |
|||
width: 142rpx; |
|||
height: 164rpx; |
|||
z-index: 7; |
|||
animation: squirrelFloat 4.6s ease-in-out infinite; |
|||
} |
|||
|
|||
@keyframes squirrelFloat { |
|||
0%, 100% { transform: translateY(0) rotate(6deg); } |
|||
50% { transform: translateY(-18rpx) rotate(-4deg); } |
|||
} |
|||
|
|||
.ph-squirrel-img { |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
width: 142rpx; |
|||
height: 142rpx; |
|||
border-radius: 50%; |
|||
background: rgba(255,255,255,0.5); |
|||
border: 3rpx solid rgba(255,255,255,0.9); |
|||
box-shadow: 0 16rpx 34rpx rgba(79,183,255,0.18); |
|||
} |
|||
|
|||
.ph-squirrel-tag { |
|||
position: absolute; |
|||
left: 38rpx; |
|||
bottom: 0; |
|||
width: 68rpx; |
|||
height: 38rpx; |
|||
line-height: 38rpx; |
|||
text-align: center; |
|||
border-radius: 999rpx; |
|||
background: rgba(255,255,255,0.82); |
|||
color: #35D6A6; |
|||
font-size: 19rpx; |
|||
font-weight: 900; |
|||
border: 1rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 10rpx 22rpx rgba(53,214,166,0.12); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,237 @@ |
|||
<template> |
|||
<view class="pm"> |
|||
<view class="pm-stamp">PLANET PASS</view> |
|||
<view class="pm-main"> |
|||
<view class="pm-left"> |
|||
<image class="pm-avatar" :src="data.avatar || defaultAvatar" mode="aspectFill"></image> |
|||
<view class="pm-info"> |
|||
<view class="pm-name">{{data.nickname || '星球居民'}}</view> |
|||
<view class="pm-sub"> |
|||
<text>{{data.level || 'C'}} 级探索者</text> |
|||
<text>连签 {{data.consecutiveSignDays || 0}} 天</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="pm-ticket"> |
|||
<text class="pm-ticket-num">{{data.myTicketCount || 0}}</text> |
|||
<text class="pm-ticket-label">星球券</text> |
|||
</view> |
|||
</view> |
|||
<view class="pm-sign" :class="{signed: data.signedToday}" @tap="onSign"> |
|||
{{data.signedToday ? '今日已盖章' : '今日签到盖章'}} |
|||
</view> |
|||
|
|||
<view class="pm-buffs" v-if="data.myBuffs && data.myBuffs.length"> |
|||
<text class="pm-buffs-label">正在生效</text> |
|||
<view class="pm-buff" v-for="(b, i) in data.myBuffs" :key="i"> |
|||
<text class="pm-buff-emoji">{{buffEmoji(b.type)}}</text> |
|||
</view> |
|||
</view> |
|||
<view class="pm-buffs pm-buffs-empty" v-else> |
|||
<text class="pm-buffs-label">暂无增益,去能量站补给</text> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
data: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
defaultAvatar: 'https://jewel-shop.oss-cn-beijing.aliyuncs.com/41cfb56caff4419b94b69d0f2303b602.png' |
|||
} |
|||
}, |
|||
methods: { |
|||
buffEmoji(type) { |
|||
const map = { |
|||
double: '2X', |
|||
shield: '盾', |
|||
lucky: 'LU', |
|||
hunt: '追', |
|||
stealth: '隐' |
|||
} |
|||
return map[type] || 'UP' |
|||
}, |
|||
onSign() { |
|||
if (this.data.signedToday) return |
|||
this.$emit('sign') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.pm { |
|||
position: relative; |
|||
margin-top: -12rpx; |
|||
padding: 30rpx 28rpx 28rpx; |
|||
border-radius: 38rpx; |
|||
background: linear-gradient(145deg, rgba(255,255,255,0.86), rgba(245,255,250,0.64)); |
|||
border: 2rpx solid rgba(255,255,255,0.9); |
|||
box-shadow: 0 22rpx 60rpx rgba(53,214,166,0.14); |
|||
backdrop-filter: blur(10px); |
|||
overflow: hidden; |
|||
transform: rotate(-1.2deg); |
|||
} |
|||
|
|||
.pm:before { |
|||
content: ''; |
|||
position: absolute; |
|||
right: -50rpx; |
|||
top: -80rpx; |
|||
width: 220rpx; |
|||
height: 220rpx; |
|||
border-radius: 50%; |
|||
background: radial-gradient(circle, rgba(79,183,255,0.28), transparent 66%); |
|||
} |
|||
|
|||
.pm-stamp { |
|||
position: absolute; |
|||
right: 26rpx; |
|||
top: 22rpx; |
|||
color: rgba(53,214,166,0.22); |
|||
font-size: 24rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 3rpx; |
|||
} |
|||
|
|||
.pm-main { |
|||
position: relative; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.pm-left { |
|||
display: flex; |
|||
align-items: center; |
|||
min-width: 0; |
|||
flex: 1; |
|||
} |
|||
|
|||
.pm-avatar { |
|||
width: 92rpx; |
|||
height: 92rpx; |
|||
border-radius: 50%; |
|||
border: 5rpx solid rgba(255,255,255,0.9); |
|||
box-shadow: 0 14rpx 28rpx rgba(53,214,166,0.18); |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.pm-info { |
|||
flex: 1; |
|||
margin-left: 18rpx; |
|||
min-width: 0; |
|||
} |
|||
|
|||
.pm-name { |
|||
color: #12342F; |
|||
font-size: 32rpx; |
|||
font-weight: 800; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.pm-sub { |
|||
margin-top: 10rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
flex-wrap: wrap; |
|||
} |
|||
|
|||
.pm-sub text { |
|||
color: #42635E; |
|||
font-size: 22rpx; |
|||
margin-right: 14rpx; |
|||
} |
|||
|
|||
.pm-ticket { |
|||
position: relative; |
|||
min-width: 132rpx; |
|||
height: 96rpx; |
|||
padding: 0 16rpx; |
|||
border-radius: 28rpx; |
|||
background: linear-gradient(145deg, rgba(255,255,255,0.96), rgba(221,248,255,0.88)); |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
border: 2rpx solid rgba(255,255,255,0.96); |
|||
box-shadow: 0 16rpx 34rpx rgba(79,183,255,0.12); |
|||
} |
|||
|
|||
.pm-ticket-num { |
|||
color: #22B889; |
|||
font-size: 36rpx; |
|||
font-weight: 900; |
|||
font-family: DIN, Arial, sans-serif; |
|||
line-height: 38rpx; |
|||
} |
|||
|
|||
.pm-ticket-label { |
|||
margin-top: 4rpx; |
|||
color: #7E9691; |
|||
font-size: 20rpx; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.pm-sign { |
|||
position: relative; |
|||
margin-top: 24rpx; |
|||
height: 66rpx; |
|||
line-height: 66rpx; |
|||
text-align: center; |
|||
border-radius: 999rpx; |
|||
background: linear-gradient(135deg, #35D6A6, #4FB7FF); |
|||
color: #FFFFFF; |
|||
font-size: 26rpx; |
|||
font-weight: 800; |
|||
box-shadow: 0 16rpx 34rpx rgba(53,214,166,0.24); |
|||
} |
|||
|
|||
.pm-sign.signed { |
|||
background: rgba(18,52,47,0.08); |
|||
color: #7E9691; |
|||
box-shadow: none; |
|||
} |
|||
|
|||
.pm-buffs { |
|||
position: relative; |
|||
margin-top: 24rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
flex-wrap: wrap; |
|||
} |
|||
|
|||
.pm-buffs-label { |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
margin-right: 14rpx; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.pm-buff { |
|||
width: 52rpx; |
|||
height: 52rpx; |
|||
border-radius: 18rpx; |
|||
background: rgba(255,255,255,0.72); |
|||
border: 1rpx solid rgba(53,214,166,0.26); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-right: 12rpx; |
|||
} |
|||
|
|||
.pm-buff-emoji { |
|||
font-size: 19rpx; |
|||
font-weight: 900; |
|||
color: #22B889; |
|||
font-family: DIN, Arial, sans-serif; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,70 @@ |
|||
<template> |
|||
<view class="pn" v-if="list && list.length"> |
|||
<view class="pn-icon">RADIO</view> |
|||
<swiper class="pn-swiper" vertical autoplay circular :interval="2800" :duration="500" :display-multiple-items="1"> |
|||
<swiper-item v-for="(item, idx) in list" :key="idx" class="pn-item"> |
|||
<text class="pn-text">{{item.content}}</text> |
|||
</swiper-item> |
|||
</swiper> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.pn { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-top: -8rpx; |
|||
padding: 0 18rpx; |
|||
height: 72rpx; |
|||
border-radius: 999rpx; |
|||
background: rgba(255,255,255,0.72); |
|||
border: 1rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 16rpx 34rpx rgba(79,183,255,0.12); |
|||
backdrop-filter: blur(8px); |
|||
transform: rotate(1.2deg); |
|||
} |
|||
|
|||
.pn-icon { |
|||
height: 42rpx; |
|||
line-height: 42rpx; |
|||
padding: 0 16rpx; |
|||
border-radius: 999rpx; |
|||
background: linear-gradient(135deg, #35D6A6, #4FB7FF); |
|||
color: #FFFFFF; |
|||
font-size: 18rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 1rpx; |
|||
margin-right: 12rpx; |
|||
} |
|||
|
|||
.pn-swiper { |
|||
flex: 1; |
|||
height: 72rpx; |
|||
} |
|||
|
|||
.pn-item { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 72rpx; |
|||
} |
|||
|
|||
.pn-text { |
|||
color: #42635E; |
|||
font-size: 24rpx; |
|||
font-weight: 600; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,218 @@ |
|||
<template> |
|||
<view class="pr"> |
|||
<view class="pr-game"> |
|||
<view class="pr-radar"> |
|||
<view class="pr-radar-line"></view> |
|||
<view class="pr-radar-dot"></view> |
|||
</view> |
|||
<view class="pr-game-copy"> |
|||
<text class="pr-kicker">SCHOOL RICH LIST</text> |
|||
<text class="pr-title">全校首富雷达</text> |
|||
<text class="pr-sub">锁定券王,发起追捕,抢回今日补给权</text> |
|||
</view> |
|||
<view class="pr-remain"> |
|||
<text>{{remainHunt}}</text> |
|||
<text>次追捕</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<scroll-view v-if="list && list.length" scroll-x class="pr-scroll" show-scrollbar="false"> |
|||
<view class="pr-list"> |
|||
<rank-item |
|||
v-for="(item, i) in list" |
|||
:key="i" |
|||
:item="item" |
|||
:index="i" |
|||
@hunt="onHunt"> |
|||
</rank-item> |
|||
</view> |
|||
</scroll-view> |
|||
<view v-else class="pr-empty"> |
|||
<text>暂无上榜居民,攒券登顶成为今日主角</text> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import rankItem from './rank-item.vue' |
|||
export default { |
|||
components: { |
|||
rankItem |
|||
}, |
|||
props: { |
|||
list: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
remainHunt: { |
|||
type: Number, |
|||
default: 0 |
|||
} |
|||
}, |
|||
methods: { |
|||
onHunt(item) { |
|||
this.$emit('hunt', item) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.pr { |
|||
margin-top: 38rpx; |
|||
} |
|||
|
|||
.pr-game { |
|||
position: relative; |
|||
display: flex; |
|||
align-items: center; |
|||
min-height: 190rpx; |
|||
box-sizing: border-box; |
|||
padding: 28rpx 24rpx; |
|||
margin-bottom: 24rpx; |
|||
border-radius: 46rpx; |
|||
background: |
|||
radial-gradient(circle at 18% 50%, rgba(255,122,89,0.14), transparent 34%), |
|||
linear-gradient(135deg, rgba(255,255,255,0.86), rgba(255,246,219,0.66)); |
|||
border: 2rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 24rpx 58rpx rgba(255,122,89,0.12); |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.pr-radar { |
|||
position: relative; |
|||
width: 126rpx; |
|||
height: 126rpx; |
|||
border-radius: 50%; |
|||
border: 2rpx solid rgba(255,122,89,0.22); |
|||
background: radial-gradient(circle, rgba(255,122,89,0.12), rgba(255,255,255,0.44)); |
|||
flex-shrink: 0; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.pr-radar:before, |
|||
.pr-radar:after { |
|||
content: ''; |
|||
position: absolute; |
|||
border-radius: 50%; |
|||
border: 1rpx solid rgba(255,122,89,0.2); |
|||
} |
|||
|
|||
.pr-radar:before { |
|||
left: 24rpx; |
|||
top: 24rpx; |
|||
width: 76rpx; |
|||
height: 76rpx; |
|||
} |
|||
|
|||
.pr-radar:after { |
|||
left: 44rpx; |
|||
top: 44rpx; |
|||
width: 36rpx; |
|||
height: 36rpx; |
|||
} |
|||
|
|||
.pr-radar-line { |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 50%; |
|||
width: 58rpx; |
|||
height: 4rpx; |
|||
border-radius: 999rpx; |
|||
transform-origin: left center; |
|||
background: linear-gradient(90deg, rgba(255,122,89,0.72), rgba(255,122,89,0)); |
|||
animation: radarSpin 2.4s linear infinite; |
|||
} |
|||
|
|||
@keyframes radarSpin { |
|||
0% { transform: rotate(0deg) translateX(0); } |
|||
100% { transform: rotate(360deg) translateX(0); } |
|||
} |
|||
|
|||
.pr-radar-dot { |
|||
position: absolute; |
|||
right: 30rpx; |
|||
top: 36rpx; |
|||
width: 14rpx; |
|||
height: 14rpx; |
|||
border-radius: 50%; |
|||
background: #FF7A59; |
|||
box-shadow: 0 0 18rpx rgba(255,122,89,0.55); |
|||
} |
|||
|
|||
.pr-game-copy { |
|||
flex: 1; |
|||
margin-left: 22rpx; |
|||
min-width: 0; |
|||
} |
|||
|
|||
.pr-kicker { |
|||
display: block; |
|||
color: #FF7A59; |
|||
font-size: 18rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 3rpx; |
|||
margin-bottom: 4rpx; |
|||
} |
|||
|
|||
.pr-title { |
|||
display: block; |
|||
color: #12342F; |
|||
font-size: 38rpx; |
|||
font-weight: 900; |
|||
letter-spacing: -1rpx; |
|||
} |
|||
|
|||
.pr-sub { |
|||
display: block; |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
margin-top: 6rpx; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.pr-remain { |
|||
color: #FFFFFF; |
|||
width: 112rpx; |
|||
height: 112rpx; |
|||
background: linear-gradient(135deg, #FF7A59, #FFB84D); |
|||
border-radius: 34rpx; |
|||
box-shadow: 0 12rpx 26rpx rgba(255,122,89,0.18); |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
flex-shrink: 0; |
|||
transform: rotate(4deg); |
|||
} |
|||
|
|||
.pr-remain text:first-child { |
|||
font-size: 40rpx; |
|||
font-weight: 900; |
|||
line-height: 42rpx; |
|||
font-family: DIN, Arial, sans-serif; |
|||
} |
|||
|
|||
.pr-remain text:last-child { |
|||
font-size: 19rpx; |
|||
font-weight: 800; |
|||
margin-top: 4rpx; |
|||
} |
|||
|
|||
.pr-scroll { |
|||
width: 100%; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.pr-list { |
|||
display: inline-flex; |
|||
padding: 4rpx 0 12rpx; |
|||
} |
|||
|
|||
.pr-empty { |
|||
padding: 60rpx 0; |
|||
text-align: center; |
|||
color: #7E9691; |
|||
font-size: 24rpx; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,250 @@ |
|||
<template> |
|||
<view class="pt"> |
|||
<view class="pt-head"> |
|||
<view> |
|||
<text class="pt-kicker">SUPPLY MAP</text> |
|||
<text class="pt-title">星球补给地图</text> |
|||
</view> |
|||
<text class="pt-sub">完成校园行动,点亮补给点</text> |
|||
</view> |
|||
<view class="pt-list"> |
|||
<view class="pt-item" v-for="(t, i) in taskCards" :key="i" :class="t.cardClass"> |
|||
<view class="pt-route-dot"></view> |
|||
<view class="pt-item-icon">{{t.icon}}</view> |
|||
<view class="pt-item-mid"> |
|||
<view class="pt-item-name">{{t.name}}</view> |
|||
<view class="pt-item-desc">{{t.description}}</view> |
|||
</view> |
|||
<view class="pt-item-btn" |
|||
:class="{auto: t.actionType==='auto', done: t.actionType==='claim' && !t.canClaim}" |
|||
@tap="onClick(t)"> |
|||
<text>+{{t.rewardTickets}}券</text> |
|||
<text>{{btnText(t)}}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
tasks: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}, |
|||
computed: { |
|||
taskCards() { |
|||
return (this.tasks || []).map((item, index) => { |
|||
return Object.assign({}, item, { |
|||
icon: this.taskEmoji(item.code), |
|||
cardClass: this.taskClass(item.code) + (index % 2 === 1 ? ' offset' : '') |
|||
}) |
|||
}) |
|||
} |
|||
}, |
|||
methods: { |
|||
taskEmoji(code) { |
|||
const map = { |
|||
waimai: '食', |
|||
group: '团', |
|||
invite: '邀', |
|||
sign: '签' |
|||
} |
|||
return map[code] || '券' |
|||
}, |
|||
taskClass(code) { |
|||
const map = { |
|||
waimai: 'type-food', |
|||
group: 'type-group', |
|||
invite: 'type-invite', |
|||
sign: 'type-sign' |
|||
} |
|||
return map[code] || 'type-other' |
|||
}, |
|||
btnText(t) { |
|||
if (t.actionType === 'auto') return '去完成' |
|||
if (t.code === 'sign') return t.canClaim ? '签到' : '已领取' |
|||
return t.canClaim ? '领取' : '已领取' |
|||
}, |
|||
onClick(t) { |
|||
if (t.actionType === 'auto') { |
|||
this.$emit('go', t) |
|||
return |
|||
} |
|||
if (!t.canClaim) return |
|||
this.$emit('claim', t) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.pt { |
|||
position: relative; |
|||
margin-top: 34rpx; |
|||
} |
|||
|
|||
.pt-head { |
|||
display: flex; |
|||
align-items: flex-end; |
|||
justify-content: space-between; |
|||
margin-bottom: 22rpx; |
|||
} |
|||
|
|||
.pt-kicker { |
|||
display: block; |
|||
color: #35D6A6; |
|||
font-size: 18rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 3rpx; |
|||
margin-bottom: 4rpx; |
|||
} |
|||
|
|||
.pt-title { |
|||
display: block; |
|||
color: #12342F; |
|||
font-size: 36rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.pt-sub { |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.pt-list { |
|||
position: relative; |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.pt-list:before { |
|||
content: ''; |
|||
position: absolute; |
|||
left: 42rpx; |
|||
right: 42rpx; |
|||
top: 102rpx; |
|||
height: 180rpx; |
|||
border-top: 3rpx dashed rgba(53,214,166,0.28); |
|||
border-radius: 50%; |
|||
transform: rotate(-7deg); |
|||
background: transparent; |
|||
} |
|||
|
|||
.pt-item { |
|||
position: relative; |
|||
width: 318rpx; |
|||
min-height: 224rpx; |
|||
box-sizing: border-box; |
|||
padding: 26rpx 22rpx 24rpx; |
|||
margin-bottom: 24rpx; |
|||
border-radius: 36rpx; |
|||
background: linear-gradient(145deg, rgba(255,255,255,0.82), rgba(244,255,249,0.64)); |
|||
border: 2rpx solid rgba(255,255,255,0.9); |
|||
box-shadow: 0 18rpx 42rpx rgba(53,214,166,0.1); |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.pt-item.offset { |
|||
margin-top: 54rpx; |
|||
transform: rotate(1.4deg); |
|||
} |
|||
|
|||
.pt-item:not(.offset) { |
|||
transform: rotate(-1deg); |
|||
} |
|||
|
|||
.pt-item:before { |
|||
content: ''; |
|||
position: absolute; |
|||
right: -36rpx; |
|||
top: -40rpx; |
|||
width: 150rpx; |
|||
height: 150rpx; |
|||
border-radius: 50%; |
|||
background: rgba(53,214,166,0.12); |
|||
} |
|||
|
|||
.pt-item.type-food:before { background: rgba(255,184,77,0.18); } |
|||
.pt-item.type-group:before { background: rgba(79,183,255,0.18); } |
|||
.pt-item.type-invite:before { background: rgba(143,124,255,0.16); } |
|||
.pt-item.type-sign:before { background: rgba(53,214,166,0.16); } |
|||
|
|||
.pt-route-dot { |
|||
position: absolute; |
|||
left: 28rpx; |
|||
top: -8rpx; |
|||
width: 20rpx; |
|||
height: 20rpx; |
|||
border-radius: 50%; |
|||
background: #35D6A6; |
|||
border: 5rpx solid rgba(255,255,255,0.9); |
|||
box-shadow: 0 6rpx 16rpx rgba(53,214,166,0.22); |
|||
} |
|||
|
|||
.pt-item-icon { |
|||
position: relative; |
|||
width: 72rpx; |
|||
height: 72rpx; |
|||
border-radius: 24rpx; |
|||
background: linear-gradient(145deg, #E5FFF1, #EAF8FF); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
color: #12342F; |
|||
font-size: 30rpx; |
|||
font-weight: 900; |
|||
box-shadow: inset 0 0 0 1rpx rgba(255,255,255,0.86); |
|||
} |
|||
|
|||
.pt-item-mid { |
|||
position: relative; |
|||
margin-top: 18rpx; |
|||
} |
|||
|
|||
.pt-item-name { |
|||
color: #12342F; |
|||
font-size: 28rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.pt-item-desc { |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
margin-top: 8rpx; |
|||
line-height: 32rpx; |
|||
min-height: 64rpx; |
|||
} |
|||
|
|||
.pt-item-btn { |
|||
position: relative; |
|||
margin-top: 18rpx; |
|||
height: 58rpx; |
|||
padding: 0 18rpx; |
|||
border-radius: 999rpx; |
|||
background: linear-gradient(135deg, #35D6A6, #4FB7FF); |
|||
color: #FFFFFF; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
font-size: 23rpx; |
|||
font-weight: 800; |
|||
box-shadow: 0 12rpx 26rpx rgba(53,214,166,0.22); |
|||
} |
|||
|
|||
.pt-item-btn.auto { |
|||
background: rgba(18,52,47,0.08); |
|||
color: #22B889; |
|||
box-shadow: none; |
|||
} |
|||
|
|||
.pt-item-btn.done { |
|||
background: rgba(18,52,47,0.06); |
|||
color: #9AA9A5; |
|||
box-shadow: none; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,251 @@ |
|||
<template> |
|||
<view class="ri" :class="cardClass"> |
|||
<view class="ri-scan"></view> |
|||
<view class="ri-topline"> |
|||
<view class="ri-rank"> |
|||
<text>#{{item.rankNo}}</text> |
|||
</view> |
|||
<text class="ri-self" v-if="item.self">ME</text> |
|||
</view> |
|||
<view class="ri-avatar-wrap"> |
|||
<image class="ri-avatar" :src="item.avatar || defaultAvatar" mode="aspectFill"></image> |
|||
<view class="ri-ring"></view> |
|||
</view> |
|||
<view class="ri-mid"> |
|||
<view class="ri-name">{{item.nickname || '神秘同学'}}</view> |
|||
<view class="ri-bounty">{{item.ticketCount}} 张星球券</view> |
|||
<view class="ri-tags"> |
|||
<text class="ri-danger">{{item.dangerLevelName || '校园玩家'}}</text> |
|||
<text class="ri-keep" v-if="item.rankKeepDays > 0">霸榜 {{item.rankKeepDays}} 天</text> |
|||
</view> |
|||
<view class="ri-action" |
|||
:class="{disabled: item.self || item.shielded}" |
|||
@tap.stop="onHunt"> |
|||
<text v-if="item.shielded">防护中</text> |
|||
<text v-else-if="item.self">榜上有我</text> |
|||
<text v-else>发起追捕</text> |
|||
</view> |
|||
<view class="ri-extra" v-if="item.bountyTickets > 0 && !item.self">额外悬赏+{{item.bountyTickets}}</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
item: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
}, |
|||
index: { |
|||
type: Number, |
|||
default: 0 |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
defaultAvatar: 'https://jewel-shop.oss-cn-beijing.aliyuncs.com/41cfb56caff4419b94b69d0f2303b602.png' |
|||
} |
|||
}, |
|||
computed: { |
|||
cardClass() { |
|||
return 'lv-' + (this.item.dangerLevel || 'C').toLowerCase() + (this.index < 3 ? ' top' : '') |
|||
} |
|||
}, |
|||
methods: { |
|||
onHunt() { |
|||
this.$emit('hunt', this.item) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.ri { |
|||
position: relative; |
|||
display: inline-flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
width: 252rpx; |
|||
min-height: 386rpx; |
|||
box-sizing: border-box; |
|||
padding: 22rpx 20rpx 20rpx; |
|||
border-radius: 42rpx; |
|||
margin-right: 22rpx; |
|||
background: linear-gradient(155deg, rgba(255,255,255,0.88), rgba(245,255,250,0.68)); |
|||
border: 2rpx solid rgba(255,255,255,0.92); |
|||
overflow: hidden; |
|||
vertical-align: top; |
|||
white-space: normal; |
|||
box-shadow: 0 22rpx 52rpx rgba(53,214,166,0.12); |
|||
} |
|||
|
|||
.ri.top { |
|||
width: 286rpx; |
|||
min-height: 416rpx; |
|||
background: linear-gradient(155deg, rgba(255,255,255,0.94), rgba(255,246,219,0.74)); |
|||
} |
|||
|
|||
.ri.lv-s, .ri.lv-sss { |
|||
border-color: rgba(255,122,89,0.48); |
|||
box-shadow: 0 24rpx 58rpx rgba(255,122,89,0.14); |
|||
} |
|||
|
|||
.ri.lv-a { |
|||
border-color: rgba(255,184,77,0.52); |
|||
} |
|||
|
|||
.ri-scan { |
|||
position: absolute; |
|||
top: 0; |
|||
left: -60%; |
|||
width: 60%; |
|||
height: 100%; |
|||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.62), transparent); |
|||
animation: scan 4.2s linear infinite; |
|||
} |
|||
|
|||
@keyframes scan { |
|||
0% { left: -60%; } |
|||
100% { left: 120%; } |
|||
} |
|||
|
|||
.ri-topline { |
|||
position: relative; |
|||
width: 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.ri-rank { |
|||
height: 42rpx; |
|||
line-height: 42rpx; |
|||
padding: 0 16rpx; |
|||
border-radius: 999rpx; |
|||
background: rgba(255,255,255,0.82); |
|||
color: #22B889; |
|||
border: 1rpx solid rgba(255,255,255,0.96); |
|||
box-shadow: 0 8rpx 18rpx rgba(53,214,166,0.1); |
|||
font-size: 22rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.ri-self { |
|||
background: linear-gradient(135deg, #35D6A6, #4FB7FF); |
|||
color: #FFFFFF; |
|||
font-size: 18rpx; |
|||
font-weight: 900; |
|||
padding: 4rpx 12rpx; |
|||
border-radius: 999rpx; |
|||
} |
|||
|
|||
.ri-avatar-wrap { |
|||
position: relative; |
|||
margin-top: 26rpx; |
|||
width: 132rpx; |
|||
height: 132rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.ri-ring { |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
border-radius: 50%; |
|||
border: 3rpx dashed rgba(53,214,166,0.42); |
|||
animation: ringRotate 10s linear infinite; |
|||
} |
|||
|
|||
@keyframes ringRotate { |
|||
0% { transform: rotate(0deg); } |
|||
100% { transform: rotate(360deg); } |
|||
} |
|||
|
|||
.ri-avatar { |
|||
width: 106rpx; |
|||
height: 106rpx; |
|||
border-radius: 34rpx; |
|||
border: 5rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 16rpx 34rpx rgba(18,52,47,0.14); |
|||
} |
|||
|
|||
.ri-mid { |
|||
position: relative; |
|||
width: 100%; |
|||
margin-top: 18rpx; |
|||
text-align: center; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.ri-name { |
|||
color: #12342F; |
|||
font-size: 28rpx; |
|||
font-weight: 900; |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.ri-bounty { |
|||
margin-top: 8rpx; |
|||
color: #22B889; |
|||
font-size: 24rpx; |
|||
font-weight: 900; |
|||
font-family: DIN, Arial, sans-serif; |
|||
} |
|||
|
|||
.ri-tags { |
|||
margin-top: 14rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
flex-wrap: wrap; |
|||
} |
|||
|
|||
.ri-danger { |
|||
color: #FF7A59; |
|||
font-size: 20rpx; |
|||
font-weight: 800; |
|||
border: 1rpx solid rgba(255,122,89,0.32); |
|||
padding: 4rpx 12rpx; |
|||
border-radius: 999rpx; |
|||
background: rgba(255,122,89,0.08); |
|||
} |
|||
|
|||
.ri-keep { |
|||
color: #7E9691; |
|||
font-size: 20rpx; |
|||
margin-top: 8rpx; |
|||
} |
|||
|
|||
.ri-action { |
|||
margin: 18rpx auto 0; |
|||
height: 58rpx; |
|||
line-height: 58rpx; |
|||
border-radius: 999rpx; |
|||
background: linear-gradient(135deg, #FF7A59, #FFB84D); |
|||
color: #fff; |
|||
font-size: 23rpx; |
|||
font-weight: 900; |
|||
box-shadow: 0 14rpx 28rpx rgba(255,122,89,0.22); |
|||
} |
|||
|
|||
.ri-action.disabled { |
|||
background: rgba(18,52,47,0.08); |
|||
color: #9AA9A5; |
|||
box-shadow: none; |
|||
} |
|||
|
|||
.ri-extra { |
|||
margin-top: 8rpx; |
|||
color: #FFB84D; |
|||
font-size: 20rpx; |
|||
font-weight: 800; |
|||
text-align: center; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,346 @@ |
|||
<template> |
|||
<view class="dr" :style="{'--sb': statusBarHeight + 'px'}"> |
|||
<view class="dr-bg"></view> |
|||
<view class="nav" :style="{paddingTop: statusBarHeight + 'px'}"> |
|||
<view class="nav-back" @tap="goBack"><text class="nav-back-icon">‹</text></view> |
|||
<view class="nav-title">开奖结果</view> |
|||
</view> |
|||
|
|||
<scroll-view scroll-y class="dr-scroll" :style="{paddingTop: (statusBarHeight + 44) + 'px'}"> |
|||
<!-- 切换 --> |
|||
<view class="dr-tabs"> |
|||
<view class="dr-tab" :class="{on: tab===0}" @tap="tab=0">最近开奖</view> |
|||
<view class="dr-tab" :class="{on: tab===1}" @tap="tab=1">我的中奖</view> |
|||
</view> |
|||
|
|||
<block v-if="tab===0"> |
|||
<view v-if="record" class="dr-card"> |
|||
<view class="dr-period">第 {{record.periodNo}} 期</view> |
|||
<view class="dr-amount"><text>¥</text>{{Number(record.poolAmount||0).toFixed(2)}}</view> |
|||
<view class="dr-meta"> |
|||
<text>参与 {{record.joinCount}} 人</text> |
|||
<text>·</text> |
|||
<text>中奖 {{record.winnerCount}} 人</text> |
|||
</view> |
|||
<view class="dr-time">开奖时间 {{record.drawTime}}</view> |
|||
</view> |
|||
<view v-else class="dr-empty">本商圈暂未开奖,敬请期待 🌌</view> |
|||
|
|||
<view class="dr-winners" v-if="winners && winners.length"> |
|||
<view class="dr-sec-title">中奖名单</view> |
|||
<view class="dr-winner" v-for="(w, i) in winners" :key="i"> |
|||
<text class="dr-w-level" :class="'lv'+w.rewardLevel">{{w.levelName}}</text> |
|||
<text class="dr-w-name">{{w.userName || '神秘居民'}}</text> |
|||
<text class="dr-w-amount">¥{{Number(w.amount||0).toFixed(2)}}</text> |
|||
</view> |
|||
</view> |
|||
</block> |
|||
|
|||
<block v-else> |
|||
<view v-if="myWinning && myWinning.length" class="dr-my"> |
|||
<view class="dr-my-item" v-for="(w, i) in myWinning" :key="i"> |
|||
<view class="dr-my-left"> |
|||
<text class="dr-w-level" :class="'lv'+w.rewardLevel">{{w.levelName}}</text> |
|||
<text class="dr-my-period">第 {{w.periodNo}} 期</text> |
|||
</view> |
|||
<text class="dr-my-amount">¥{{Number(w.amount||0).toFixed(2)}}</text> |
|||
<view class="dr-my-btn" :class="{done: w.isReceived===1}" @tap="receive(w)"> |
|||
{{w.isReceived===1 ? '已领取' : '领取'}} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view v-else class="dr-empty">还没有中奖记录,继续攒券瓜分奖池</view> |
|||
</block> |
|||
<view style="height:60rpx;"></view> |
|||
</scroll-view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
statusBarHeight: 20, |
|||
tab: 0, |
|||
userId: '', |
|||
regionId: '', |
|||
record: null, |
|||
winners: [], |
|||
myWinning: [] |
|||
} |
|||
}, |
|||
onLoad() { |
|||
const sys = uni.getSystemInfoSync() |
|||
this.statusBarHeight = sys.statusBarHeight || 20 |
|||
this.userId = uni.getStorageSync('id') || '' |
|||
try { |
|||
const area = uni.getStorageSync('area') |
|||
if (area) this.regionId = JSON.parse(area).id || '' |
|||
} catch (e) {} |
|||
if (!this.regionId) { |
|||
this.tui.toast('未获取到校区信息,开奖仅限本区域内进行') |
|||
return |
|||
} |
|||
this.loadResult() |
|||
this.loadMyWinning() |
|||
}, |
|||
methods: { |
|||
loadResult() { |
|||
this.tui.request('/app/planet/draw/result', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId |
|||
}).then((res) => { |
|||
if (res.code == 200 && res.result) { |
|||
this.record = res.result.record |
|||
this.winners = res.result.winners || [] |
|||
} |
|||
}) |
|||
}, |
|||
loadMyWinning() { |
|||
this.tui.request('/app/planet/draw/myWinning', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId |
|||
}, false, false, true).then((res) => { |
|||
if (res.code == 200) this.myWinning = res.result || [] |
|||
}) |
|||
}, |
|||
receive(w) { |
|||
if (w.isReceived === 1) return |
|||
this.tui.request('/app/planet/draw/receive', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId, |
|||
winnerId: w.id |
|||
}).then((res) => { |
|||
this.tui.toast(res.message, 1500, res.code == 200) |
|||
if (res.code == 200) this.loadMyWinning() |
|||
}) |
|||
}, |
|||
goBack() { |
|||
uni.navigateBack({ delta: 1 }) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.dr { |
|||
min-height: 100vh; |
|||
background: linear-gradient(155deg, #F3FFF4 0%, #EAF8FF 46%, #F7EEFF 100%); |
|||
color: #12342F; |
|||
} |
|||
|
|||
.dr-bg { |
|||
position: fixed; |
|||
top: 0; left: 0; right: 0; height: 500rpx; |
|||
background: |
|||
radial-gradient(circle at 78% 12%, rgba(79,183,255,0.28), transparent 42%), |
|||
radial-gradient(circle at 12% 30%, rgba(53,214,166,0.22), transparent 40%); |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.nav { |
|||
position: fixed; |
|||
top: 0; left: 0; right: 0; |
|||
height: 44px; |
|||
z-index: 20; |
|||
display: flex; |
|||
align-items: flex-end; |
|||
justify-content: center; |
|||
background: linear-gradient(180deg, rgba(243,255,244,0.9), rgba(243,255,244,0)); |
|||
} |
|||
|
|||
.nav-back { |
|||
position: absolute; |
|||
left: 20rpx; |
|||
bottom: 0; |
|||
height: 44px; |
|||
width: 60rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.nav-back-icon { |
|||
color: #12342F; |
|||
font-size: 48rpx; |
|||
} |
|||
|
|||
.nav-title { |
|||
color: #12342F; |
|||
font-size: 34rpx; |
|||
font-weight: 800; |
|||
padding-bottom: 6rpx; |
|||
} |
|||
|
|||
.dr-scroll { |
|||
height: 100vh; |
|||
box-sizing: border-box; |
|||
padding: 0 32rpx; |
|||
} |
|||
|
|||
.dr-tabs { |
|||
display: flex; |
|||
margin-top: 20rpx; |
|||
background: rgba(255,255,255,0.68); |
|||
border-radius: 36rpx; |
|||
padding: 6rpx; |
|||
border: 1rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 16rpx 34rpx rgba(53,214,166,0.1); |
|||
} |
|||
|
|||
.dr-tab { |
|||
flex: 1; |
|||
height: 64rpx; |
|||
line-height: 64rpx; |
|||
text-align: center; |
|||
border-radius: 32rpx; |
|||
color: #42635E; |
|||
font-size: 26rpx; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.dr-tab.on { |
|||
background: linear-gradient(135deg, #35D6A6, #4FB7FF); |
|||
color: #FFFFFF; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.dr-card { |
|||
margin-top: 28rpx; |
|||
padding: 40rpx; |
|||
border-radius: 42rpx; |
|||
background: linear-gradient(150deg, rgba(255,255,255,0.9), rgba(255,248,222,0.72)); |
|||
border: 2rpx solid rgba(255,255,255,0.92); |
|||
text-align: center; |
|||
box-shadow: 0 24rpx 60rpx rgba(255,184,77,0.14); |
|||
} |
|||
|
|||
.dr-period { |
|||
color: #7E9691; |
|||
font-size: 24rpx; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.dr-amount { |
|||
margin-top: 12rpx; |
|||
color: #22B889; |
|||
font-size: 72rpx; |
|||
font-weight: 800; |
|||
} |
|||
|
|||
.dr-amount text { |
|||
font-size: 36rpx; |
|||
} |
|||
|
|||
.dr-meta { |
|||
margin-top: 14rpx; |
|||
color: #42635E; |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.dr-meta text { |
|||
margin: 0 8rpx; |
|||
} |
|||
|
|||
.dr-time { |
|||
margin-top: 10rpx; |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
} |
|||
|
|||
.dr-empty { |
|||
margin-top: 120rpx; |
|||
text-align: center; |
|||
color: #7E9691; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.dr-sec-title { |
|||
margin: 32rpx 0 18rpx; |
|||
color: #12342F; |
|||
font-size: 30rpx; |
|||
font-weight: 900; |
|||
} |
|||
|
|||
.dr-winner { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 22rpx 24rpx; |
|||
margin-bottom: 14rpx; |
|||
border-radius: 28rpx; |
|||
background: rgba(255,255,255,0.72); |
|||
border: 1rpx solid rgba(255,255,255,0.9); |
|||
box-shadow: 0 12rpx 28rpx rgba(53,214,166,0.08); |
|||
} |
|||
|
|||
.dr-w-level { |
|||
font-size: 22rpx; |
|||
padding: 2rpx 14rpx; |
|||
border-radius: 8rpx; |
|||
background: rgba(53,214,166,0.14); |
|||
color: #22B889; |
|||
} |
|||
|
|||
.dr-w-level.lv1 { background: rgba(255,122,89,0.14); color: #FF7A59; } |
|||
.dr-w-level.lv2 { background: rgba(255,184,77,0.18); color: #C98716; } |
|||
|
|||
.dr-w-name { |
|||
flex: 1; |
|||
margin-left: 18rpx; |
|||
color: #12342F; |
|||
font-size: 26rpx; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.dr-w-amount { |
|||
color: #22B889; |
|||
font-size: 28rpx; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.dr-my-item { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 26rpx 24rpx; |
|||
margin-top: 18rpx; |
|||
border-radius: 30rpx; |
|||
background: rgba(255,255,255,0.74); |
|||
border: 1rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 12rpx 30rpx rgba(53,214,166,0.08); |
|||
} |
|||
|
|||
.dr-my-left { |
|||
flex: 1; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.dr-my-period { |
|||
margin-top: 10rpx; |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
} |
|||
|
|||
.dr-my-amount { |
|||
color: #22B889; |
|||
font-size: 32rpx; |
|||
font-weight: 800; |
|||
margin-right: 20rpx; |
|||
} |
|||
|
|||
.dr-my-btn { |
|||
padding: 0 26rpx; |
|||
height: 60rpx; |
|||
line-height: 60rpx; |
|||
border-radius: 30rpx; |
|||
background: linear-gradient(135deg, #35D6A6, #4FB7FF); |
|||
color: #FFFFFF; |
|||
font-size: 24rpx; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.dr-my-btn.done { |
|||
background: rgba(18,52,47,0.08); |
|||
color: #9AA9A5; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,717 @@ |
|||
<template> |
|||
<view class="planet" :style="{'--statusbar': statusBarHeight + 'px'}"> |
|||
<view class="planet-bg"> |
|||
<view class="bg-aura bg-aura-a"></view> |
|||
<view class="bg-aura bg-aura-b"></view> |
|||
<view class="bg-aura bg-aura-c"></view> |
|||
<view class="bg-space-dust bg-space-dust-a"></view> |
|||
<view class="bg-space-dust bg-space-dust-b"></view> |
|||
<view class="bg-shooting bg-shooting-a"></view> |
|||
<view class="bg-shooting bg-shooting-b"></view> |
|||
<view class="bg-orbit bg-orbit-a"></view> |
|||
<view class="bg-orbit bg-orbit-b"></view> |
|||
<view class="bg-star" v-for="(s, i) in stars" :key="i" :style="s"></view> |
|||
<view class="bg-planet bg-planet-a"></view> |
|||
<view class="bg-planet bg-planet-b"></view> |
|||
</view> |
|||
|
|||
<view class="nav" :style="{paddingTop: statusBarHeight + 'px'}"> |
|||
<view class="nav-back" @tap="goBack"> |
|||
<text class="nav-back-icon">‹</text> |
|||
</view> |
|||
<view class="nav-title">白嫖星球</view> |
|||
<view class="nav-right"> |
|||
<text class="nav-link" @tap="goTicketLog">明细</text> |
|||
<text class="nav-link nav-link-main" @tap="goDrawResult">开奖</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<scroll-view scroll-y class="planet-scroll" :style="{paddingTop: (statusBarHeight + 44) + 'px'}"> |
|||
<!-- 骨架屏 --> |
|||
<view v-if="loading" class="skeleton"> |
|||
<view class="sk-block sk-header"></view> |
|||
<view class="sk-block sk-me"></view> |
|||
<view class="sk-block sk-row"></view> |
|||
<view class="sk-block sk-list"></view> |
|||
</view> |
|||
|
|||
<block v-else> |
|||
<planet-header :data="home"></planet-header> |
|||
|
|||
<planet-news :list="home.newsList"></planet-news> |
|||
|
|||
<planet-me |
|||
:data="home" |
|||
@sign="onSign" |
|||
@openbox="openBox"> |
|||
</planet-me> |
|||
|
|||
<planet-box |
|||
:available="home.boxAvailable" |
|||
:opening="boxOpening" |
|||
@open="openBox"> |
|||
</planet-box> |
|||
|
|||
<planet-tasks |
|||
:tasks="home.tasks" |
|||
@claim="onClaimTask"> |
|||
</planet-tasks> |
|||
|
|||
<planet-rank |
|||
:list="home.rankList" |
|||
:remain-hunt="home.remainHunt" |
|||
@hunt="onHunt"> |
|||
</planet-rank> |
|||
|
|||
<buff-shop |
|||
:list="home.buffShop" |
|||
:my-ticket="home.myTicketCount" |
|||
@buy="onBuyBuff"> |
|||
</buff-shop> |
|||
|
|||
<view class="bottom-space"></view> |
|||
</block> |
|||
</scroll-view> |
|||
|
|||
<!-- 追捕浮层 --> |
|||
<hunt-modal |
|||
:show="huntModal.show" |
|||
:phase="huntModal.phase" |
|||
:result="huntModal.result" |
|||
:target="huntModal.target" |
|||
@close="closeHunt"> |
|||
</hunt-modal> |
|||
|
|||
<view v-if="boxResult.show" class="box-result-mask" @tap="boxResult.show=false"> |
|||
<view class="box-result" @tap.stop> |
|||
<view class="box-result-burst"></view> |
|||
<view class="box-result-icon">BLIND BOX</view> |
|||
<view class="box-result-title">{{boxResult.data.rewardName}}</view> |
|||
<view class="box-result-desc">{{boxResult.data.message}}</view> |
|||
<view class="box-result-btn" @tap="boxResult.show=false">收下了</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import planetHeader from '@/package1/components/planet/planet-header.vue' |
|||
import planetMe from '@/package1/components/planet/planet-me.vue' |
|||
import planetTasks from '@/package1/components/planet/planet-tasks.vue' |
|||
import planetBox from '@/package1/components/planet/planet-box.vue' |
|||
import planetRank from '@/package1/components/planet/planet-rank.vue' |
|||
import huntModal from '@/package1/components/planet/hunt-modal.vue' |
|||
import buffShop from '@/package1/components/planet/buff-shop.vue' |
|||
import planetNews from '@/package1/components/planet/planet-news.vue' |
|||
|
|||
export default { |
|||
components: { |
|||
planetHeader, |
|||
planetMe, |
|||
planetTasks, |
|||
planetBox, |
|||
planetRank, |
|||
huntModal, |
|||
buffShop, |
|||
planetNews |
|||
}, |
|||
data() { |
|||
return { |
|||
statusBarHeight: 20, |
|||
loading: true, |
|||
userId: '', |
|||
regionId: '', |
|||
nickname: '', |
|||
avatar: '', |
|||
college: '', |
|||
home: { |
|||
poolAmount: 0, |
|||
joinCount: 0, |
|||
myTicketCount: 0, |
|||
myRankNo: 0, |
|||
remainHunt: 3, |
|||
tasks: [], |
|||
rankList: [], |
|||
buffShop: [], |
|||
newsList: [], |
|||
myBuffs: [] |
|||
}, |
|||
boxOpening: false, |
|||
boxResult: { |
|||
show: false, |
|||
data: {} |
|||
}, |
|||
huntModal: { |
|||
show: false, |
|||
phase: 'searching', |
|||
result: null, |
|||
target: {} |
|||
} |
|||
} |
|||
}, |
|||
computed: { |
|||
stars() { |
|||
const arr = [] |
|||
for (let n = 1; n <= 46; n++) { |
|||
const top = (n * 29) % 100 |
|||
const left = (n * 47) % 100 |
|||
const delay = (n % 12) / 2 |
|||
const size = (n % 4) + 1 |
|||
arr.push(`top:${top}%;left:${left}%;width:${size}px;height:${size}px;animation-delay:${delay}s;`) |
|||
} |
|||
return arr |
|||
} |
|||
}, |
|||
onLoad() { |
|||
const sys = uni.getSystemInfoSync() |
|||
this.statusBarHeight = sys.statusBarHeight || 20 |
|||
this.userId = uni.getStorageSync('id') || '' |
|||
this.nickname = uni.getStorageSync('nickName') || uni.getStorageSync('nickname') || '' |
|||
this.avatar = uni.getStorageSync('avatarUrl') || uni.getStorageSync('avatar') || '' |
|||
try { |
|||
const area = uni.getStorageSync('area') |
|||
if (area) { |
|||
this.regionId = JSON.parse(area).id || '' |
|||
} |
|||
} catch (e) {} |
|||
this.loadHome() |
|||
}, |
|||
methods: { |
|||
loadHome(silent) { |
|||
if (!this.userId) { |
|||
this.tui.toast('请先登录') |
|||
return |
|||
} |
|||
if (!this.regionId) { |
|||
this.loading = false |
|||
this.tui.toast('未获取到校区信息,白嫖星球仅限本区域内进行') |
|||
return |
|||
} |
|||
if (!silent) this.loading = true |
|||
this.tui.request('/app/planet/home', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId, |
|||
nickname: this.nickname, |
|||
avatar: this.avatar, |
|||
college: this.college |
|||
}, false, false, true).then((res) => { |
|||
this.loading = false |
|||
if (res.code == 200 && res.result) { |
|||
this.home = res.result |
|||
} else if (res.message) { |
|||
this.tui.toast(res.message) |
|||
} |
|||
}).catch(() => { |
|||
this.loading = false |
|||
}) |
|||
}, |
|||
onSign() { |
|||
this.tui.request('/app/planet/sign', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId |
|||
}).then((res) => { |
|||
this.tui.toast(res.message, 1500, res.code == 200) |
|||
if (res.code == 200) this.loadHome(true) |
|||
}) |
|||
}, |
|||
openBox() { |
|||
if (!this.home.boxAvailable || this.boxOpening) return |
|||
this.boxOpening = true |
|||
this.tui.request('/app/planet/box/open', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId |
|||
}).then((res) => { |
|||
setTimeout(() => { |
|||
this.boxOpening = false |
|||
if (res.code == 200 && res.result) { |
|||
this.boxResult.data = res.result |
|||
this.boxResult.show = true |
|||
this.loadHome(true) |
|||
} else { |
|||
this.tui.toast(res.message) |
|||
} |
|||
}, 800) |
|||
}).catch(() => { |
|||
this.boxOpening = false |
|||
}) |
|||
}, |
|||
onClaimTask(task) { |
|||
if (task.code === 'sign') { |
|||
this.onSign() |
|||
return |
|||
} |
|||
this.tui.request('/app/planet/task/claim', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId, |
|||
taskCode: task.code |
|||
}).then((res) => { |
|||
this.tui.toast(res.message, 1500, res.code == 200) |
|||
if (res.code == 200) this.loadHome(true) |
|||
}) |
|||
}, |
|||
onHunt(item) { |
|||
if (item.self) { |
|||
this.tui.toast('不能追捕自己') |
|||
return |
|||
} |
|||
if (item.shielded) { |
|||
this.tui.toast('目标已开启防护罩') |
|||
return |
|||
} |
|||
if (this.home.remainHunt <= 0) { |
|||
this.tui.toast('今日追捕次数已用完') |
|||
return |
|||
} |
|||
this.huntModal.show = true |
|||
this.huntModal.phase = 'searching' |
|||
this.huntModal.result = null |
|||
this.huntModal.target = item |
|||
// 动画阶段推进 |
|||
setTimeout(() => { this.huntModal.phase = 'locking' }, 900) |
|||
setTimeout(() => { this.huntModal.phase = 'chasing' }, 1800) |
|||
this.tui.request('/app/planet/hunt', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId, |
|||
toUserId: item.userId |
|||
}, false, false, true).then((res) => { |
|||
setTimeout(() => { |
|||
if (res.code == 200 && res.result) { |
|||
this.huntModal.result = res.result |
|||
this.huntModal.phase = 'result' |
|||
this.loadHome(true) |
|||
} else { |
|||
this.huntModal.show = false |
|||
this.tui.toast(res.message) |
|||
} |
|||
}, 2600) |
|||
}).catch(() => { |
|||
this.huntModal.show = false |
|||
}) |
|||
}, |
|||
closeHunt() { |
|||
this.huntModal.show = false |
|||
this.huntModal.result = null |
|||
}, |
|||
onBuyBuff(buff) { |
|||
if (buff.active) { |
|||
this.tui.toast('该增益正在生效中') |
|||
return |
|||
} |
|||
if (this.home.myTicketCount < buff.costTickets) { |
|||
this.tui.toast('星球券不足') |
|||
return |
|||
} |
|||
this.tui.modal('确认购买', `消耗 ${buff.costTickets} 张星球券购买「${buff.name}」?`, true, (ok) => { |
|||
if (!ok) return |
|||
this.tui.request('/app/planet/buff/buy', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId, |
|||
buffId: buff.id |
|||
}).then((res) => { |
|||
this.tui.toast(res.code == 200 ? '购买成功' : res.message, 1500, res.code == 200) |
|||
if (res.code == 200) this.loadHome(true) |
|||
}) |
|||
}) |
|||
}, |
|||
goDrawResult() { |
|||
uni.navigateTo({ |
|||
url: '/package1/planet/drawResult' |
|||
}) |
|||
}, |
|||
goTicketLog() { |
|||
uni.navigateTo({ |
|||
url: '/package1/planet/ticketLog' |
|||
}) |
|||
}, |
|||
goBack() { |
|||
uni.navigateBack({ |
|||
delta: 1, |
|||
fail() { |
|||
uni.switchTab({ url: '/pages/index/index' }) |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.planet { |
|||
min-height: 100vh; |
|||
background: |
|||
radial-gradient(circle at 50% 260rpx, rgba(255,255,255,0.72), rgba(255,255,255,0) 360rpx), |
|||
linear-gradient(155deg, #F3FFF4 0%, #EAF8FF 42%, #F7EEFF 76%, #FFF8DE 100%); |
|||
position: relative; |
|||
overflow: hidden; |
|||
color: #12342F; |
|||
} |
|||
|
|||
.planet-bg { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
z-index: 0; |
|||
overflow: hidden; |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.bg-aura { |
|||
position: absolute; |
|||
border-radius: 50%; |
|||
filter: blur(12rpx); |
|||
opacity: 0.72; |
|||
animation: auraFloat 8s ease-in-out infinite; |
|||
} |
|||
|
|||
.bg-aura-a { |
|||
width: 520rpx; |
|||
height: 520rpx; |
|||
right: -160rpx; |
|||
top: 74rpx; |
|||
background: radial-gradient(circle, rgba(79,183,255,0.34), rgba(79,183,255,0)); |
|||
} |
|||
|
|||
.bg-aura-b { |
|||
width: 460rpx; |
|||
height: 460rpx; |
|||
left: -180rpx; |
|||
top: 360rpx; |
|||
background: radial-gradient(circle, rgba(53,214,166,0.35), rgba(53,214,166,0)); |
|||
animation-delay: -2.5s; |
|||
} |
|||
|
|||
.bg-aura-c { |
|||
width: 420rpx; |
|||
height: 420rpx; |
|||
right: -110rpx; |
|||
top: 860rpx; |
|||
background: radial-gradient(circle, rgba(143,124,255,0.22), rgba(143,124,255,0)); |
|||
animation-delay: -4s; |
|||
} |
|||
|
|||
.bg-space-dust { |
|||
position: absolute; |
|||
border-radius: 50%; |
|||
background: |
|||
radial-gradient(circle, rgba(255,255,255,0.9) 0 2rpx, transparent 3rpx), |
|||
radial-gradient(circle, rgba(53,214,166,0.5) 0 2rpx, transparent 3rpx), |
|||
radial-gradient(circle, rgba(143,124,255,0.38) 0 2rpx, transparent 3rpx); |
|||
background-size: 86rpx 92rpx, 124rpx 116rpx, 156rpx 148rpx; |
|||
opacity: 0.38; |
|||
animation: dustDrift 16s linear infinite; |
|||
} |
|||
|
|||
.bg-space-dust-a { |
|||
left: -120rpx; |
|||
top: 120rpx; |
|||
width: 980rpx; |
|||
height: 860rpx; |
|||
} |
|||
|
|||
.bg-space-dust-b { |
|||
left: -180rpx; |
|||
top: 900rpx; |
|||
width: 1000rpx; |
|||
height: 760rpx; |
|||
animation-delay: -6s; |
|||
opacity: 0.24; |
|||
} |
|||
|
|||
@keyframes dustDrift { |
|||
0% { transform: translate3d(0, 0, 0); } |
|||
100% { transform: translate3d(-86rpx, 92rpx, 0); } |
|||
} |
|||
|
|||
.bg-shooting { |
|||
position: absolute; |
|||
width: 180rpx; |
|||
height: 3rpx; |
|||
border-radius: 999rpx; |
|||
background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,0.9), rgba(79,183,255,0.25)); |
|||
transform: rotate(-30deg); |
|||
animation: shooting 5.6s linear infinite; |
|||
} |
|||
|
|||
.bg-shooting-a { |
|||
right: -160rpx; |
|||
top: 240rpx; |
|||
} |
|||
|
|||
.bg-shooting-b { |
|||
right: -160rpx; |
|||
top: 780rpx; |
|||
width: 130rpx; |
|||
animation-delay: -2.8s; |
|||
opacity: 0.72; |
|||
} |
|||
|
|||
@keyframes shooting { |
|||
0% { transform: translate3d(180rpx, -80rpx, 0) rotate(-30deg); opacity: 0; } |
|||
10% { opacity: 1; } |
|||
60% { opacity: 1; } |
|||
100% { transform: translate3d(-760rpx, 300rpx, 0) rotate(-30deg); opacity: 0; } |
|||
} |
|||
|
|||
@keyframes auraFloat { |
|||
0%, 100% { transform: translate3d(0, 0, 0) scale(1); } |
|||
50% { transform: translate3d(18rpx, -34rpx, 0) scale(1.06); } |
|||
} |
|||
|
|||
.bg-orbit { |
|||
position: absolute; |
|||
border: 2rpx solid rgba(255,255,255,0.72); |
|||
border-radius: 50%; |
|||
transform: rotate(-18deg); |
|||
} |
|||
|
|||
.bg-orbit-a { |
|||
width: 920rpx; |
|||
height: 300rpx; |
|||
left: -60rpx; |
|||
top: 250rpx; |
|||
opacity: 0.34; |
|||
} |
|||
|
|||
.bg-orbit-b { |
|||
width: 720rpx; |
|||
height: 210rpx; |
|||
right: -190rpx; |
|||
top: 680rpx; |
|||
opacity: 0.26; |
|||
} |
|||
|
|||
.bg-star { |
|||
position: absolute; |
|||
background: rgba(255,255,255,0.92); |
|||
border-radius: 50%; |
|||
box-shadow: 0 0 12rpx rgba(79,183,255,0.45); |
|||
opacity: 0.55; |
|||
animation: twinkle 3.6s ease-in-out infinite; |
|||
} |
|||
|
|||
@keyframes twinkle { |
|||
0%, 100% { opacity: 0.28; transform: scale(0.8); } |
|||
50% { opacity: 0.85; transform: scale(1.28); } |
|||
} |
|||
|
|||
.bg-planet { |
|||
position: absolute; |
|||
border-radius: 50%; |
|||
opacity: 0.8; |
|||
box-shadow: inset -18rpx -22rpx 42rpx rgba(18,52,47,0.08), 0 22rpx 60rpx rgba(53,214,166,0.18); |
|||
} |
|||
|
|||
.bg-planet-a { |
|||
width: 120rpx; |
|||
height: 120rpx; |
|||
right: 34rpx; |
|||
top: 106rpx; |
|||
background: radial-gradient(circle at 32% 28%, #FFFFFF 0%, #BAF7CF 32%, #7DE2FF 100%); |
|||
animation: float 8.5s ease-in-out infinite; |
|||
} |
|||
|
|||
.bg-planet-b { |
|||
width: 92rpx; |
|||
height: 92rpx; |
|||
left: 24rpx; |
|||
top: 760rpx; |
|||
background: radial-gradient(circle at 30% 30%, #FFFFFF 0%, #FFE7A8 36%, #FFB7D1 100%); |
|||
animation: float 10s ease-in-out infinite reverse; |
|||
} |
|||
|
|||
@keyframes float { |
|||
0%, 100% { transform: translateY(0) translateX(0); } |
|||
50% { transform: translateY(-24rpx) translateX(12rpx); } |
|||
} |
|||
|
|||
.nav { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 44px; |
|||
z-index: 20; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
box-sizing: content-box; |
|||
background: linear-gradient(180deg, rgba(243,255,244,0.88), rgba(243,255,244,0)); |
|||
} |
|||
|
|||
.nav-back { |
|||
position: absolute; |
|||
left: 20rpx; |
|||
bottom: 0; |
|||
height: 44px; |
|||
width: 60rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.nav-back-icon { |
|||
color: #12342F; |
|||
font-size: 48rpx; |
|||
font-weight: 300; |
|||
} |
|||
|
|||
.nav-title { |
|||
color: #12342F; |
|||
font-size: 34rpx; |
|||
font-weight: 800; |
|||
letter-spacing: 1rpx; |
|||
align-self: flex-end; |
|||
padding-bottom: 6rpx; |
|||
} |
|||
|
|||
.nav-right { |
|||
position: absolute; |
|||
right: 24rpx; |
|||
bottom: 6rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.nav-link { |
|||
font-size: 26rpx; |
|||
color: #42635E; |
|||
margin-left: 16rpx; |
|||
padding: 8rpx 16rpx; |
|||
border-radius: 999rpx; |
|||
background: rgba(255,255,255,0.62); |
|||
border: 1rpx solid rgba(255,255,255,0.9); |
|||
box-shadow: 0 10rpx 24rpx rgba(53,214,166,0.1); |
|||
} |
|||
|
|||
.nav-link-main { |
|||
color: #FFFFFF; |
|||
background: linear-gradient(135deg, #35D6A6, #4FB7FF); |
|||
border-color: rgba(255,255,255,0.78); |
|||
} |
|||
|
|||
.planet-scroll { |
|||
position: relative; |
|||
z-index: 5; |
|||
height: 100vh; |
|||
box-sizing: border-box; |
|||
padding-left: 22rpx; |
|||
padding-right: 22rpx; |
|||
} |
|||
|
|||
.bottom-space { |
|||
height: 60rpx; |
|||
} |
|||
|
|||
/* 骨架屏 */ |
|||
.skeleton { |
|||
padding-top: 22rpx; |
|||
} |
|||
|
|||
.sk-block { |
|||
border-radius: 36rpx; |
|||
background: linear-gradient(90deg, rgba(255,255,255,0.45) 25%, rgba(255,255,255,0.9) 37%, rgba(255,255,255,0.45) 63%); |
|||
background-size: 400% 100%; |
|||
animation: shimmer 1.4s ease infinite; |
|||
margin-bottom: 24rpx; |
|||
box-shadow: 0 18rpx 42rpx rgba(53,214,166,0.1); |
|||
} |
|||
|
|||
.sk-header { height: 520rpx; border-radius: 48rpx; } |
|||
.sk-me { height: 150rpx; } |
|||
.sk-row { height: 220rpx; } |
|||
.sk-list { height: 330rpx; } |
|||
|
|||
@keyframes shimmer { |
|||
0% { background-position: 100% 50%; } |
|||
100% { background-position: 0 50%; } |
|||
} |
|||
|
|||
/* 宝箱结果 */ |
|||
.box-result-mask { |
|||
position: fixed; |
|||
top: 0; left: 0; right: 0; bottom: 0; |
|||
background: rgba(18,52,47,0.28); |
|||
backdrop-filter: blur(8px); |
|||
z-index: 60; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.box-result { |
|||
position: relative; |
|||
width: 540rpx; |
|||
padding: 62rpx 40rpx 42rpx; |
|||
border-radius: 48rpx; |
|||
background: linear-gradient(155deg, rgba(255,255,255,0.92), rgba(244,255,249,0.78)); |
|||
border: 2rpx solid rgba(255,255,255,0.9); |
|||
box-shadow: 0 34rpx 80rpx rgba(53,214,166,0.24); |
|||
text-align: center; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.box-result-burst { |
|||
position: absolute; |
|||
top: -60rpx; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
width: 400rpx; |
|||
height: 400rpx; |
|||
background: radial-gradient(circle, rgba(255,184,77,0.36), transparent 62%); |
|||
animation: pulse 1.6s ease-in-out infinite; |
|||
} |
|||
|
|||
@keyframes pulse { |
|||
0%, 100% { transform: translateX(-50%) scale(0.9); opacity: 0.6; } |
|||
50% { transform: translateX(-50%) scale(1.1); opacity: 1; } |
|||
} |
|||
|
|||
.box-result-icon { |
|||
display: inline-flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 190rpx; |
|||
height: 190rpx; |
|||
border-radius: 46rpx; |
|||
background: linear-gradient(145deg, #FFFFFF, #DDF8FF 48%, #E8DFFF); |
|||
color: #22B889; |
|||
font-size: 24rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 1rpx; |
|||
position: relative; |
|||
animation: bounce 1s ease infinite; |
|||
box-shadow: inset -16rpx -20rpx 34rpx rgba(143,124,255,0.16), 0 22rpx 48rpx rgba(79,183,255,0.18); |
|||
} |
|||
|
|||
@keyframes bounce { |
|||
0%, 100% { transform: translateY(0); } |
|||
50% { transform: translateY(-12rpx); } |
|||
} |
|||
|
|||
.box-result-title { |
|||
margin-top: 20rpx; |
|||
color: #12342F; |
|||
font-size: 36rpx; |
|||
font-weight: 800; |
|||
} |
|||
|
|||
.box-result-desc { |
|||
margin-top: 12rpx; |
|||
color: #42635E; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.box-result-btn { |
|||
margin-top: 36rpx; |
|||
height: 80rpx; |
|||
line-height: 80rpx; |
|||
border-radius: 40rpx; |
|||
background: linear-gradient(135deg, #35D6A6, #4FB7FF); |
|||
color: #FFFFFF; |
|||
font-size: 30rpx; |
|||
font-weight: 700; |
|||
box-shadow: 0 18rpx 36rpx rgba(53,214,166,0.25); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,385 @@ |
|||
<template> |
|||
<view class="tl" :style="{'--sb': statusBarHeight + 'px'}"> |
|||
<view class="tl-bg"></view> |
|||
<view class="nav" :style="{paddingTop: statusBarHeight + 'px'}"> |
|||
<view class="nav-back" @tap="goBack"><text class="nav-back-icon">‹</text></view> |
|||
<view class="nav-title">星球券明细</view> |
|||
</view> |
|||
|
|||
<scroll-view scroll-y class="tl-scroll" :style="{paddingTop: (statusBarHeight + 44) + 'px'}" |
|||
@scrolltolower="loadMore"> |
|||
<!-- 汇总卡片 --> |
|||
<view class="tl-sum"> |
|||
<view class="tl-sum-glow"></view> |
|||
<view class="tl-sum-label">当前持有星球券</view> |
|||
<view class="tl-sum-value"> |
|||
<text class="tl-sum-num">{{balance}}</text> |
|||
<text class="tl-sum-unit">张</text> |
|||
</view> |
|||
<view class="tl-sum-tip">星球券永久有效,囤越多瓜分越多</view> |
|||
</view> |
|||
|
|||
<!-- 骨架屏 --> |
|||
<view v-if="loading && list.length===0" class="tl-sk"> |
|||
<view class="tl-sk-item" v-for="n in 6" :key="n"></view> |
|||
</view> |
|||
|
|||
<!-- 明细列表 --> |
|||
<view v-else-if="list.length" class="tl-list"> |
|||
<view class="tl-item" v-for="(item, i) in list" :key="i"> |
|||
<view class="tl-icon" :class="'t-'+(item.type||'other')">{{typeIcon(item.type)}}</view> |
|||
<view class="tl-mid"> |
|||
<text class="tl-name">{{item.remark || typeName(item.type)}}</text> |
|||
<text class="tl-time">{{item.createTime}}</text> |
|||
</view> |
|||
<view class="tl-right"> |
|||
<text class="tl-change" :class="item.changeCount >= 0 ? 'up' : 'down'"> |
|||
{{item.changeCount >= 0 ? '+' : ''}}{{item.changeCount}} |
|||
</text> |
|||
<text class="tl-balance">余 {{item.balance}}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="tl-foot"> |
|||
<text v-if="loading">加载中…</text> |
|||
<text v-else-if="noMore">— 没有更多了 —</text> |
|||
<text v-else @tap="loadMore">点击加载更多</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 空态 --> |
|||
<view v-else class="tl-empty"> |
|||
<text class="tl-empty-icon">NO LOG</text> |
|||
<text class="tl-empty-text">还没有星球券记录</text> |
|||
<text class="tl-empty-tip">完成任务、下单、邀请好友都能获得星球券</text> |
|||
</view> |
|||
|
|||
<view style="height:60rpx;"></view> |
|||
</scroll-view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
statusBarHeight: 20, |
|||
userId: '', |
|||
regionId: '', |
|||
balance: 0, |
|||
list: [], |
|||
pageNumber: 1, |
|||
pageSize: 15, |
|||
total: 0, |
|||
loading: false, |
|||
noMore: false |
|||
} |
|||
}, |
|||
onLoad() { |
|||
const sys = uni.getSystemInfoSync() |
|||
this.statusBarHeight = sys.statusBarHeight || 20 |
|||
this.userId = uni.getStorageSync('id') || '' |
|||
try { |
|||
const area = uni.getStorageSync('area') |
|||
if (area) this.regionId = JSON.parse(area).id || '' |
|||
} catch (e) {} |
|||
this.loadPage(true) |
|||
}, |
|||
methods: { |
|||
loadPage(reset) { |
|||
if (this.loading) return |
|||
if (!this.userId) { |
|||
this.tui.toast('请先登录') |
|||
return |
|||
} |
|||
if (reset) { |
|||
this.pageNumber = 1 |
|||
this.noMore = false |
|||
} |
|||
this.loading = true |
|||
this.tui.request('/app/planet/ticket/log', 'POST', { |
|||
userId: this.userId, |
|||
regionId: this.regionId, |
|||
pageNumber: this.pageNumber, |
|||
pageSize: this.pageSize |
|||
}, false, false, true).then((res) => { |
|||
this.loading = false |
|||
if (res.code == 200 && res.result) { |
|||
const records = res.result.records || [] |
|||
this.total = res.result.total || 0 |
|||
if (reset) { |
|||
this.list = records |
|||
// 取最新一条余额作为当前持有 |
|||
if (records.length) this.balance = records[0].balance |
|||
} else { |
|||
this.list = this.list.concat(records) |
|||
} |
|||
if (this.list.length >= this.total || records.length < this.pageSize) { |
|||
this.noMore = true |
|||
} |
|||
} |
|||
}).catch(() => { |
|||
this.loading = false |
|||
}) |
|||
}, |
|||
loadMore() { |
|||
if (this.loading || this.noMore) return |
|||
this.pageNumber++ |
|||
this.loadPage(false) |
|||
}, |
|||
typeIcon(type) { |
|||
const map = { |
|||
order: '食', group: '团', invite: '邀', sign: '签', |
|||
box: '盒', hunt: '追', buff: '能', draw: '奖' |
|||
} |
|||
return map[type] || '券' |
|||
}, |
|||
typeName(type) { |
|||
const map = { |
|||
order: '外卖订单', group: '团购订单', invite: '邀请好友', sign: '每日签到', |
|||
box: '幸运宝箱', hunt: '星际追捕', buff: '购买增益', draw: '开奖瓜分' |
|||
} |
|||
return map[type] || '星球券变动' |
|||
}, |
|||
goBack() { |
|||
uni.navigateBack({ delta: 1 }) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.tl { |
|||
min-height: 100vh; |
|||
background: linear-gradient(155deg, #F3FFF4 0%, #EAF8FF 48%, #F7EEFF 100%); |
|||
color: #12342F; |
|||
} |
|||
|
|||
.tl-bg { |
|||
position: fixed; |
|||
top: 0; left: 0; right: 0; height: 520rpx; |
|||
background: |
|||
radial-gradient(circle at 78% 14%, rgba(53,214,166,0.26), transparent 44%), |
|||
radial-gradient(circle at 18% 32%, rgba(143,124,255,0.18), transparent 42%); |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.nav { |
|||
position: fixed; |
|||
top: 0; left: 0; right: 0; |
|||
height: 44px; |
|||
z-index: 20; |
|||
display: flex; |
|||
align-items: flex-end; |
|||
justify-content: center; |
|||
background: linear-gradient(180deg, rgba(243,255,244,0.9), rgba(243,255,244,0)); |
|||
} |
|||
|
|||
.nav-back { |
|||
position: absolute; |
|||
left: 20rpx; |
|||
bottom: 0; |
|||
height: 44px; |
|||
width: 60rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.nav-back-icon { color: #12342F; font-size: 48rpx; font-weight: 300; } |
|||
|
|||
.nav-title { |
|||
color: #12342F; |
|||
font-size: 34rpx; |
|||
font-weight: 800; |
|||
letter-spacing: 1rpx; |
|||
padding-bottom: 6rpx; |
|||
} |
|||
|
|||
.tl-scroll { |
|||
height: 100vh; |
|||
box-sizing: border-box; |
|||
padding: 0 28rpx; |
|||
} |
|||
|
|||
/* 汇总卡 */ |
|||
.tl-sum { |
|||
position: relative; |
|||
margin-top: 20rpx; |
|||
padding: 48rpx 40rpx 40rpx; |
|||
border-radius: 44rpx; |
|||
background: linear-gradient(150deg, rgba(255,255,255,0.9), rgba(226,255,241,0.7)); |
|||
border: 2rpx solid rgba(255,255,255,0.92); |
|||
overflow: hidden; |
|||
box-shadow: 0 24rpx 62rpx rgba(53,214,166,0.14); |
|||
} |
|||
|
|||
.tl-sum-glow { |
|||
position: absolute; |
|||
top: -120rpx; right: -80rpx; |
|||
width: 320rpx; height: 320rpx; |
|||
background: radial-gradient(circle, rgba(53,214,166,0.28), transparent 65%); |
|||
animation: tl-pulse 3s ease-in-out infinite; |
|||
} |
|||
|
|||
@keyframes tl-pulse { |
|||
0%, 100% { transform: scale(0.85); opacity: 0.55; } |
|||
50% { transform: scale(1.1); opacity: 0.95; } |
|||
} |
|||
|
|||
.tl-sum-label { |
|||
position: relative; |
|||
color: #42635E; |
|||
font-size: 26rpx; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.tl-sum-value { |
|||
position: relative; |
|||
margin-top: 12rpx; |
|||
display: flex; |
|||
align-items: baseline; |
|||
} |
|||
|
|||
.tl-sum-num { |
|||
font-size: 84rpx; |
|||
font-weight: 800; |
|||
color: #22B889; |
|||
font-family: DIN, Arial, sans-serif; |
|||
} |
|||
|
|||
.tl-sum-unit { |
|||
margin-left: 12rpx; |
|||
font-size: 28rpx; |
|||
color: #42635E; |
|||
} |
|||
|
|||
.tl-sum-tip { |
|||
position: relative; |
|||
margin-top: 16rpx; |
|||
font-size: 24rpx; |
|||
color: #7E9691; |
|||
} |
|||
|
|||
/* 骨架 */ |
|||
.tl-sk { margin-top: 28rpx; } |
|||
.tl-sk-item { |
|||
height: 120rpx; |
|||
border-radius: 22rpx; |
|||
margin-bottom: 20rpx; |
|||
background: linear-gradient(90deg, rgba(255,255,255,0.45) 25%, rgba(255,255,255,0.9) 37%, rgba(255,255,255,0.45) 63%); |
|||
background-size: 400% 100%; |
|||
animation: tl-shimmer 1.4s ease infinite; |
|||
} |
|||
|
|||
@keyframes tl-shimmer { |
|||
0% { background-position: 100% 50%; } |
|||
100% { background-position: 0 50%; } |
|||
} |
|||
|
|||
/* 列表 */ |
|||
.tl-list { margin-top: 28rpx; } |
|||
|
|||
.tl-item { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 26rpx 24rpx; |
|||
margin-bottom: 18rpx; |
|||
border-radius: 30rpx; |
|||
background: rgba(255,255,255,0.74); |
|||
border: 2rpx solid rgba(255,255,255,0.92); |
|||
box-shadow: 0 12rpx 30rpx rgba(53,214,166,0.08); |
|||
} |
|||
|
|||
.tl-icon { |
|||
width: 76rpx; |
|||
height: 76rpx; |
|||
border-radius: 20rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
font-size: 40rpx; |
|||
background: rgba(53,214,166,0.12); |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.tl-icon.t-buff, .tl-icon.t-hunt { background: rgba(255,122,89,0.14); } |
|||
.tl-icon.t-draw, .tl-icon.t-box { background: rgba(255,184,77,0.16); } |
|||
|
|||
.tl-mid { |
|||
flex: 1; |
|||
margin-left: 22rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
min-width: 0; |
|||
} |
|||
|
|||
.tl-name { |
|||
color: #12342F; |
|||
font-size: 28rpx; |
|||
font-weight: 700; |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.tl-time { |
|||
margin-top: 8rpx; |
|||
color: #7E9691; |
|||
font-size: 22rpx; |
|||
} |
|||
|
|||
.tl-right { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: flex-end; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.tl-change { |
|||
font-size: 34rpx; |
|||
font-weight: 700; |
|||
font-family: DIN, Arial, sans-serif; |
|||
} |
|||
|
|||
.tl-change.up { color: #22B889; } |
|||
.tl-change.down { color: #FF7A59; } |
|||
|
|||
.tl-balance { |
|||
margin-top: 6rpx; |
|||
font-size: 22rpx; |
|||
color: #7E9691; |
|||
} |
|||
|
|||
.tl-foot { |
|||
text-align: center; |
|||
color: #7E9691; |
|||
font-size: 24rpx; |
|||
padding: 24rpx 0 8rpx; |
|||
} |
|||
|
|||
/* 空态 */ |
|||
.tl-empty { |
|||
margin-top: 140rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
} |
|||
|
|||
.tl-empty-icon { |
|||
width: 180rpx; |
|||
height: 180rpx; |
|||
line-height: 180rpx; |
|||
text-align: center; |
|||
border-radius: 50%; |
|||
background: rgba(255,255,255,0.72); |
|||
border: 2rpx solid rgba(255,255,255,0.92); |
|||
color: #35D6A6; |
|||
font-size: 28rpx; |
|||
font-weight: 900; |
|||
letter-spacing: 2rpx; |
|||
box-shadow: 0 20rpx 44rpx rgba(53,214,166,0.12); |
|||
} |
|||
.tl-empty-text { margin-top: 24rpx; color: #42635E; font-size: 30rpx; font-weight: 800; } |
|||
.tl-empty-tip { margin-top: 12rpx; color: #7E9691; font-size: 24rpx; } |
|||
</style> |
|||
Loading…
Reference in new issue