wangfukang 1 week ago
parent
commit
80f401df7e
  1. 45
      package1/components/planet/planet-adventure-entry.vue
  2. 1
      package1/components/planet/planet-box.vue
  3. 255
      package1/components/planet/planet-daily-loop.vue
  4. 26
      package1/components/planet/planet-header.vue
  5. 1
      package1/components/planet/planet-me.vue
  6. 1
      package1/components/planet/planet-rank.vue
  7. 415
      package1/planet/adventure.vue
  8. 48
      package1/planet/drawResult.vue
  9. 369
      package1/planet/index.vue
  10. 298
      package1/planet/more.vue
  11. 306
      package1/planet/pkHall.vue
  12. 317
      package1/planet/rank.vue
  13. 46
      package1/planet/ticketLog.vue

45
package1/components/planet/planet-adventure-entry.vue

@ -1,15 +1,33 @@
<template>
<view>
<view class="pa" @tap="$emit('start')">
<view class="pa-badge">开始助推</view>
<view class="pa-left">
<view class="pa-kicker">COLLEGE ROCKET</view>
<view class="pa-title">学院助推赛</view>
<view class="pa-sub">校园版羊了个羊 · 每天2分钟 · 为学院争地标</view>
<view class="pa-sub">玩一局有机会获得更多星球券为学院争地标</view>
<!-- <view class="pa-cta">开始助推</view> -->
</view>
<view class="pa-ship">
<view class="pa-squirrel">🚀</view>
<view class="pa-flame"></view>
</view>
</view>
<view class="pa pa-pk" @tap.stop="$emit('arena')">
<view class="pa-badge">开始PK</view>
<view class="pa-left">
<view class="pa-kicker">COLLEGE ROCKET</view>
<view class="pa-title">星球擂台赛</view>
<view class="pa-sub">看看谁才是PK王</view>
<!-- <view class="pa-cta">开始PK</view> -->
</view>
<view class="pa-ship">
<view class="pa-squirrel">🚀</view>
<view class="pa-flame"></view>
</view>
</view>
</view>
</template>
<script>
@ -17,14 +35,27 @@
</script>
<style lang="scss" scoped>
.pa { margin-top: 22rpx; min-height: 180rpx; padding: 28rpx; border-radius: 42rpx; background: linear-gradient(135deg, rgba(255,255,255,0.92), rgba(232,246,255,0.78)); border: 2rpx solid rgba(255,255,255,0.92); box-shadow: 0 22rpx 50rpx rgba(79,183,255,0.14); display: flex; justify-content: space-between; align-items: center; overflow: hidden; position: relative; }
.pa:before { content: ''; position: absolute; right: -60rpx; top: -80rpx; width: 260rpx; height: 260rpx; border-radius: 50%; background: radial-gradient(circle, rgba(255,184,77,0.32), transparent 66%); }
.pa { margin-top: 22rpx; min-height: 210rpx; padding: 30rpx; border-radius: 42rpx; background: radial-gradient(circle at 92% 20%, rgba(255,184,77,0.36), transparent 32%), linear-gradient(135deg, rgba(255,255,255,0.96), rgba(232,246,255,0.78)); border: 4rpx solid rgba(255,184,77,0.58); box-shadow: 0 24rpx 56rpx rgba(255,156,66,0.18), inset 0 0 0 2rpx rgba(255,255,255,0.72); display: flex; justify-content: space-between; align-items: center; overflow: hidden; position: relative; }
.pa:before { content: ''; position: absolute; right: -60rpx; top: -80rpx; width: 300rpx; height: 300rpx; border-radius: 50%; background: radial-gradient(circle, rgba(255,184,77,0.38), transparent 66%); }
.pa:after { content: ''; position: absolute; left: 24rpx; right: 24rpx; bottom: 12rpx; height: 10rpx; border-radius: 999rpx; background: linear-gradient(90deg, rgba(255,156,66,0.24), rgba(79,183,255,0.18)); }
.pa-pk { background: radial-gradient(circle at 90% 18%, rgba(124,58,237,0.25), transparent 34%), radial-gradient(circle at 15% 100%, rgba(56,189,248,0.20), transparent 42%), linear-gradient(135deg, rgba(255,255,255,0.98), rgba(245,239,255,0.86) 48%, rgba(232,247,255,0.76)); border-color: rgba(124,58,237,0.38); box-shadow: 0 24rpx 56rpx rgba(124,58,237,0.14), inset 0 0 0 2rpx rgba(255,255,255,0.76); }
.pa-pk:before { background: radial-gradient(circle, rgba(124,58,237,0.30), transparent 66%); }
.pa-pk:after { background: linear-gradient(90deg, rgba(124,58,237,0.22), rgba(56,189,248,0.20)); }
.pa-left { position: relative; z-index: 1; padding-right: 18rpx; }
.pa-badge { position: absolute; right: 28rpx; top: 22rpx; z-index: 2; height: 44rpx; line-height: 44rpx; padding: 0 18rpx; border-radius: 999rpx; background: linear-gradient(135deg, #FF7A59, #FFB84D); color: #FFFFFF; font-size: 20rpx; font-weight: 900; box-shadow: 0 12rpx 24rpx rgba(255,122,89,0.2); }
.pa-pk .pa-badge { background: linear-gradient(135deg, #7C3AED, #38BDF8); box-shadow: 0 12rpx 26rpx rgba(124,58,237,0.20); }
.pa-arena { position: absolute; right: 28rpx; top: 76rpx; z-index: 2; height: 48rpx; line-height: 48rpx; padding: 0 20rpx; border-radius: 999rpx; background: linear-gradient(135deg, #7C3AED, #38BDF8); color: #FFFFFF; font-size: 21rpx; font-weight: 900; box-shadow: 0 12rpx 28rpx rgba(124,58,237,0.22); }
.pa-kicker { color: #FF9C42; font-size: 20rpx; font-weight: 900; letter-spacing: 2rpx; }
.pa-title { margin-top: 8rpx; color: #12342F; font-size: 38rpx; font-weight: 900; }
.pa-sub { margin-top: 10rpx; color: #6B817D; font-size: 24rpx; }
.pa-ship { position: relative; width: 150rpx; height: 110rpx; border-radius: 56rpx 56rpx 40rpx 40rpx; background: linear-gradient(145deg, #FFFFFF, #DDF8FF 50%, #FFE5AE); box-shadow: inset -12rpx -16rpx 28rpx rgba(79,183,255,0.14), 0 18rpx 42rpx rgba(255,156,66,0.18); animation: fly 2s ease-in-out infinite; }
.pa-pk .pa-kicker { color: #7C3AED; }
.pa-title { margin-top: 8rpx; color: #12342F; font-size: 44rpx; font-weight: 900; }
.pa-sub { margin-top: 10rpx; color: #6B817D; font-size: 24rpx; line-height: 1.38; max-width: 430rpx; }
.pa-cta { margin-top: 18rpx; display: inline-flex; align-items: center; justify-content: center; height: 54rpx; padding: 0 26rpx; border-radius: 999rpx; background: linear-gradient(135deg, #35D6A6, #4FB7FF); color: #FFFFFF; font-size: 23rpx; font-weight: 900; box-shadow: 0 12rpx 24rpx rgba(53,214,166,0.18); }
.pa-ship { position: relative; z-index: 1; width: 156rpx; height: 118rpx; margin-top: 40rpx; border-radius: 58rpx 58rpx 42rpx 42rpx; background: linear-gradient(145deg, #FFFFFF, #DDF8FF 50%, #FFE5AE); box-shadow: inset -12rpx -16rpx 28rpx rgba(79,183,255,0.14), 0 18rpx 42rpx rgba(255,156,66,0.18); flex-shrink: 0; }
.pa-pk .pa-ship { background: linear-gradient(145deg, #FFFFFF, #EEE7FF 48%, #DDF8FF); box-shadow: inset -12rpx -16rpx 28rpx rgba(124,58,237,0.12), 0 18rpx 42rpx rgba(56,189,248,0.18); }
.pa-squirrel { position: absolute; left: 38rpx; top: 28rpx; width: 70rpx; height: 48rpx; line-height: 48rpx; border-radius: 999rpx; background: #8B5A2B; color: #fff; font-size: 20rpx; font-weight: 900; text-align: center; }
.pa-flame { position: absolute; right: -18rpx; top: 38rpx; width: 40rpx; height: 26rpx; border-radius: 50%; background: linear-gradient(90deg, #FFB84D, rgba(255,184,77,0)); animation: flame .4s ease-in-out infinite; }
.pa-pk .pa-squirrel { background: #5B21B6; }
.pa-flame { position: absolute; right: -18rpx; top: 38rpx; width: 40rpx; height: 26rpx; border-radius: 50%; background: linear-gradient(90deg, #FFB84D, rgba(255,184,77,0)); }
.pa-pk .pa-flame { background: linear-gradient(90deg, #38BDF8, rgba(56,189,248,0)); }
@keyframes fly { 0%,100%{ transform: translateY(0); } 50%{ transform: translateY(-10rpx); } }
@keyframes flame { 0%,100%{ transform: scaleX(.8); opacity: .7; } 50%{ transform: scaleX(1.2); opacity: 1; } }
</style>

1
package1/components/planet/planet-box.vue

@ -81,7 +81,6 @@
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 {

255
package1/components/planet/planet-daily-loop.vue

@ -3,56 +3,87 @@
<view class="dl-top">
<view>
<view class="dl-kicker">2 MIN DAILY</view>
<view class="dl-title">今天就做这几步</view>
<view class="dl-sub">收券看事件反搜投奖池90秒走人</view>
<view class="dl-title">{{progressTitle}}</view>
<view class="dl-sub">完成任务可获得星球券与开奖权重</view>
</view>
<view class="dl-clock">{{data.minutesToDraw || 0}}min</view>
<view class="dl-map" @tap="$emit('more')">
<text>星球补给地图</text>
<text>进入</text>
</view>
<view class="dl-pool">
<view class="dl-pool-main">
<text class="dl-pool-label">今晚现金奖池</text>
<text class="dl-pool-money">{{poolAmount}}</text>
</view>
<view class="dl-prob">
<text>{{data.myProbability || 0}}%</text>
<text>我的概率</text>
<!-- <view class="progress-overview">
<view class="progress-row">
<text>今日进度 {{doneCount}}/3</text>
<text>{{progressPercent}}%</text>
</view>
<view class="progress-track">
<view class="progress-fill" :style="{width: progressPercent + '%'}"></view>
</view>
</view> -->
<view class="dl-stat">
<!-- <view class="dl-events">
<view class="dl-event" v-for="(e,i) in events" :key="i">{{e}}</view>
</view> -->
<view
class="main-task"
:class="{done: taskDone('pool')}"
@tap="onJoin">
<view class="main-copy">
<view class="main-icon icon-rocket"></view>
<view>
<text>{{data.todayCollectedTickets || 0}}</text>
<text>今日收券</text>
<view class="main-title">投入星球券</view>
<view class="main-desc">参与今晚奖金池瓜分</view>
</view>
<view>
<text>{{data.myPoolTickets || 0}}</text>
<text>已投奖池</text>
</view>
<view>
<text>{{data.poolJoinCount || 0}}</text>
<text>参与同学</text>
</view>
<view class="main-status">{{taskDone('pool') ? '已参与' : '立即参与'}}</view>
<view class="main-boost">预计提升中奖概率 +{{boostText}}%</view>
<view class="main-arrow"></view>
</view>
<view class="dl-events">
<view class="dl-event" v-for="(e,i) in events" :key="i">{{e}}</view>
<view class="sub-task-list">
<view
class="sub-task sign"
:class="{done: taskDone('sign')}"
@tap="onCollect">
<view class="sub-head">
<view class="task-icon icon-spark"></view>
<view class="task-badge">{{taskDone('sign') ? '✓ 已完成' : '待签到'}}</view>
</view>
<view class="sub-title">签到收券</view>
<view class="sub-desc">奖励 +1 星球券</view>
</view>
<view
class="sub-task hunt"
:class="{done: taskDone('hunt')}"
@tap="onRevenge">
<view class="sub-head">
<view class="task-icon icon-gift"></view>
<view class="task-badge">{{taskDone('hunt') ? '✓ 已完成' : '去搜查 →'}}</view>
</view>
<view class="sub-title">星球搜查令</view>
<view class="sub-desc">随机搜查白嫖得券</view>
</view>
</view>
<view class="dl-actions">
<view class="dl-action collect" @tap="$emit('collect')">
<text>1</text>
<text>{{collectText}}</text>
<view class="dl-stat">
<view class="stat-card collected">
<text>{{data.todayCollectedTickets || 0}}</text>
<text>今日收券</text>
</view>
<view class="dl-action revenge" @tap="$emit('revenge')">
<text>2</text>
<text>{{data.hasRevengeTarget ? '反搜一下' : '随机搜查'}}</text>
<view class="stat-card pooled">
<text>{{data.myPoolTickets || 0}}</text>
<text>已投奖池</text>
</view>
<view class="dl-action join" @tap="$emit('join')">
<text>3</text>
<text>{{joinText}}</text>
<view class="stat-card probability">
<text>{{data.myProbability || 0}}%</text>
<text>中奖概率</text>
</view>
</view>
<view v-if="rewardFloat.show" class="reward-float" :class="rewardFloat.type">{{rewardFloat.text}}</view>
<view v-if="flying" class="ticket-fly"></view>
</view>
</template>
@ -60,49 +91,155 @@
export default {
props: {
data: { type: Object, default: () => ({}) },
poolAmount: { type: [String, Number], default: 0 }
myTicketCount: { type: Number, default: 0 }
},
data() {
return {
flying: false,
flyTimer: null,
rewardFloat: {
show: false,
text: '',
type: ''
},
rewardTimer: null
}
},
computed: {
events() {
return this.data.events || []
},
collectText() {
if (!this.data.signedToday) return '签到收券'
if (this.data.boxAvailable) return '开补给箱'
return '已收完'
doneCount() {
let count = 0
if (this.taskDone('pool')) count += 1
if (this.taskDone('sign')) count += 1
if (this.taskDone('hunt')) count += 1
return count
},
progressPercent() {
return Math.round((this.doneCount / 3) * 100)
},
progressTitle() {
const left = 3 - this.doneCount
return left > 0 ? ('离瓜分奖金池还差 ' + left + ' 步') : '今日白嫖进度已完成'
},
boostText() {
const current = Number(this.data.myProbability || 0)
const suggested = Number(this.data.suggestedProbability || 0)
if (suggested > current) return (suggested - current).toFixed(2)
return '1.00'
}
},
beforeDestroy() {
if (this.flyTimer) clearTimeout(this.flyTimer)
if (this.rewardTimer) clearTimeout(this.rewardTimer)
},
methods: {
taskDone(type) {
if (type === 'sign') return !!this.data.signedToday && !this.data.boxAvailable
if (type === 'hunt') return !!this.data.searchedToday || !!this.data.huntedToday || (this.data.remainSearchCount === 0)
if (type === 'pool') return (this.data.myPoolTickets || 0) > 0
return false
},
onCollect() {
this.playReward('+1 星球券', 'sign')
this.$emit('collect')
},
onRevenge() {
this.playReward('随机奖励', 'hunt')
this.$emit('revenge')
},
joinText() {
const n = this.data.suggestedAddTickets || 1
return '投' + n + '券冲奖池'
playReward(text, type) {
if (this.rewardTimer) clearTimeout(this.rewardTimer)
this.rewardFloat = {
show: true,
text,
type
}
this.rewardTimer = setTimeout(() => {
this.rewardFloat.show = false
}, 800)
},
onJoin() {
if (this.flying) return
if (this.myTicketCount <= 0) {
this.$emit('join')
return
}
this.flying = true
this.playReward('+开奖权重', 'pool')
this.$emit('join')
if (this.flyTimer) clearTimeout(this.flyTimer)
this.flyTimer = setTimeout(() => {
this.flying = false
}, 940)
}
}
}
</script>
<style lang="scss" scoped>
.dl { margin-top: 24rpx; padding: 28rpx; border-radius: 44rpx; background: linear-gradient(155deg, rgba(255,255,255,0.92), rgba(239,255,249,0.78)); border: 2rpx solid rgba(255,255,255,0.92); box-shadow: 0 26rpx 60rpx rgba(53,214,166,0.14); overflow: hidden; position: relative; }
.dl { margin-top: -20rpx; padding: 28rpx; border-radius: 44rpx; background: linear-gradient(155deg, rgba(255,255,255,0.92), rgba(239,255,249,0.78)); border: 2rpx solid rgba(255,255,255,0.92); box-shadow: 0 26rpx 60rpx rgba(53,214,166,0.14); overflow: visible; position: relative; }
.dl:before { content: ''; position: absolute; right: -90rpx; top: -120rpx; width: 320rpx; height: 320rpx; border-radius: 50%; background: radial-gradient(circle, rgba(79,183,255,0.26), transparent 68%); }
.dl-top { position: relative; z-index: 1; display: flex; align-items: flex-start; justify-content: space-between; }
.dl-kicker { color: #59CBB5; font-size: 20rpx; font-weight: 900; letter-spacing: 2rpx; }
.dl-title { margin-top: 6rpx; color: #12342F; font-size: 42rpx; font-weight: 900; }
.dl-sub { margin-top: 8rpx; color: #6B817D; font-size: 24rpx; }
.dl-clock { padding: 14rpx 18rpx; border-radius: 999rpx; background: rgba(255,255,255,0.82); color: #22B889; font-size: 24rpx; font-weight: 900; }
.dl-pool { position: relative; z-index: 1; margin-top: 28rpx; display: flex; justify-content: space-between; align-items: center; padding: 26rpx; border-radius: 34rpx; background: linear-gradient(135deg, rgba(255,255,255,0.86), rgba(232,246,255,0.72)); }
.dl-pool-main { display: flex; flex-direction: column; }
.dl-pool-label { color: #6B817D; font-size: 24rpx; }
.dl-pool-money { margin-top: 8rpx; color: #12342F; font-size: 50rpx; font-weight: 900; }
.dl-prob { width: 132rpx; height: 132rpx; border-radius: 46rpx; background: linear-gradient(145deg, #35D6A6, #4FB7FF); color: #fff; display: flex; flex-direction: column; align-items: center; justify-content: center; box-shadow: 0 18rpx 40rpx rgba(53,214,166,0.24); }
.dl-prob text:first-child { font-size: 34rpx; font-weight: 900; }
.dl-prob text:last-child { font-size: 20rpx; margin-top: 4rpx; }
.dl-stat { margin-top: 18rpx; display: flex; gap: 14rpx; }
.dl-stat view { flex: 1; padding: 18rpx 10rpx; border-radius: 26rpx; background: rgba(255,255,255,0.66); display: flex; flex-direction: column; align-items: center; }
.dl-stat text:first-child { color: #12342F; font-size: 30rpx; font-weight: 900; }
.dl-stat text:last-child { color: #6B817D; font-size: 20rpx; margin-top: 4rpx; }
.dl-map { width: 146rpx; min-height: 82rpx; padding: 12rpx 10rpx; border-radius: 28rpx; background: linear-gradient(145deg, #FFFFFF, #E5FFF1); color: #22B889; display: flex; flex-direction: column; align-items: center; justify-content: center; box-shadow: 0 14rpx 28rpx rgba(53,214,166,0.16); border: 2rpx solid rgba(255,255,255,0.96); flex-shrink: 0; }
.dl-map text:first-child { font-size: 21rpx; font-weight: 900; line-height: 1.18; text-align: center; }
.dl-map text:last-child { margin-top: 8rpx; padding: 4rpx 14rpx; border-radius: 999rpx; background: linear-gradient(135deg, #35D6A6, #4FB7FF); color: #FFFFFF; font-size: 18rpx; font-weight: 900; }
.progress-overview { position: relative; z-index: 1; margin-top: 20rpx; padding: 18rpx 20rpx; border-radius: 30rpx; background: rgba(255,255,255,0.54); border: 1px solid rgba(255,255,255,.7); box-shadow: inset 0 1rpx 0 rgba(255,255,255,0.86); }
.progress-row { display: flex; justify-content: space-between; color: #42635E; font-size: 22rpx; font-weight: 900; }
.progress-row text:last-child { color: #22B889; font-family: DIN, Arial, sans-serif; }
.progress-track { margin-top: 14rpx; height: 14rpx; border-radius: 999rpx; background: rgba(18,52,47,0.08); overflow: hidden; }
.progress-fill { height: 100%; border-radius: inherit; background: linear-gradient(90deg, #34D399, #60A5FA); box-shadow: 0 0 20rpx rgba(52,211,153,0.28); transition: width .2s ease; }
.dl-events { margin-top: 18rpx; }
.dl-event { margin-top: 10rpx; padding: 14rpx 18rpx; border-radius: 24rpx; background: rgba(255,255,255,0.62); color: #42635E; font-size: 24rpx; }
.dl-actions { margin-top: 22rpx; display: flex; gap: 14rpx; }
.dl-action { flex: 1; min-height: 94rpx; border-radius: 30rpx; display: flex; flex-direction: column; align-items: center; justify-content: center; color: #12342F; font-size: 23rpx; font-weight: 900; background: rgba(255,255,255,0.78); }
.dl-action text:first-child { width: 34rpx; height: 34rpx; line-height: 34rpx; text-align: center; border-radius: 50%; background: #22B889; color: #fff; font-size: 20rpx; margin-bottom: 8rpx; }
.dl-action.join { background: linear-gradient(135deg, #35D6A6, #4FB7FF); color: #fff; box-shadow: 0 18rpx 36rpx rgba(53,214,166,0.22); }
.dl-action.join text:first-child { background: rgba(255,255,255,0.28); }
.main-task { position: relative; z-index: 1; margin-top: 22rpx; height: 170rpx; padding: 24rpx 154rpx 24rpx 24rpx; box-sizing: border-box; border-radius: 32rpx; background: linear-gradient(135deg, #FFF7EC, #FFE7C8); border: 1px solid rgba(255,255,255,.78); box-shadow: 0 20rpx 42rpx rgba(255,184,107,0.18), inset 0 1rpx 0 rgba(255,255,255,0.9); overflow: hidden; transition: transform .2s ease; }
.main-task:active, .sub-task:active { transform: scale(.97); }
.main-task.done { filter: saturate(.82); box-shadow: 0 0 30rpx rgba(52,211,153,.25), 0 20rpx 42rpx rgba(255,184,107,0.12); }
.main-task:before { content: ''; position: absolute; right: -70rpx; top: -80rpx; width: 220rpx; height: 220rpx; border-radius: 50%; background: radial-gradient(circle, rgba(255,255,255,0.72), transparent 66%); }
.main-copy { position: relative; z-index: 1; display: flex; align-items: center; }
.main-icon { position: relative; width: 54rpx; height: 54rpx; margin-right: 16rpx; flex-shrink: 0; }
.main-title { color: #5C3310; font-size: 34rpx; font-weight: 900; white-space: nowrap; }
.main-desc { margin-top: 8rpx; color: #9B7043; font-size: 22rpx; font-weight: 800; white-space: nowrap; }
.main-status { position: absolute; right: 76rpx; top: 26rpx; z-index: 1; height: 46rpx; line-height: 46rpx; padding: 0 18rpx; border-radius: 999rpx; background: rgba(255,255,255,0.66); color: #F08322; font-size: 21rpx; font-weight: 900; }
.main-boost { position: absolute; left: 24rpx; bottom: 20rpx; z-index: 1; color: #C27724; font-size: 21rpx; font-weight: 900; }
.main-arrow { position: absolute; right: 28rpx; top: 58rpx; z-index: 1; color: rgba(240,131,34,0.72); font-size: 56rpx; font-weight: 900; }
.sub-task-list { position: relative; z-index: 1; margin-top: 16rpx; display: flex; gap: 14rpx; }
.sub-task { position: relative; flex: 1; height: 148rpx; box-sizing: border-box; padding: 16rpx; border-radius: 30rpx; background: rgba(255,255,255,0.58); backdrop-filter: blur(20px); border: 1px solid rgba(255,255,255,.72); box-shadow: 0 14rpx 30rpx rgba(53,214,166,0.1), inset 0 1rpx 0 rgba(255,255,255,0.84); overflow: hidden; transition: transform .2s ease; }
.sub-task.done { filter: saturate(.72); box-shadow: 0 0 30rpx rgba(52,211,153,.22), 0 12rpx 28rpx rgba(53,214,166,0.08); }
.sub-head { display: flex; align-items: center; justify-content: space-between; }
.task-icon { position: relative; width: 30rpx; height: 30rpx; border-radius: 10rpx; flex-shrink: 0; }
.icon-spark { background: linear-gradient(145deg, rgba(52,211,153,0.18), rgba(52,211,153,0.38)); }
.icon-spark:before { content: ''; position: absolute; left: 11rpx; top: 3rpx; width: 5rpx; height: 20rpx; border-radius: 999rpx; background: #34D399; }
.icon-spark:after { content: ''; position: absolute; left: 3rpx; top: 11rpx; width: 20rpx; height: 5rpx; border-radius: 999rpx; background: #34D399; }
.icon-gift { background: linear-gradient(145deg, rgba(96,165,250,0.2), rgba(96,165,250,0.42)); }
.icon-gift:before { content: ''; position: absolute; left: 4rpx; right: 4rpx; top: 10rpx; height: 12rpx; border-radius: 3rpx; background: #60A5FA; }
.icon-gift:after { content: ''; position: absolute; left: 11rpx; top: 4rpx; width: 5rpx; height: 20rpx; border-radius: 999rpx; background: rgba(255,255,255,0.82); }
.icon-rocket { background: linear-gradient(145deg, rgba(255,184,107,0.2), rgba(255,184,107,0.46)); border-radius: 50% 50% 42% 42%; }
.icon-rocket:before { content: ''; position: absolute; left: 9rpx; top: 4rpx; width: 8rpx; height: 14rpx; border-radius: 999rpx; background: #FFB86B; }
.icon-rocket:after { content: ''; position: absolute; left: 8rpx; bottom: -3rpx; width: 10rpx; height: 8rpx; border-radius: 50%; background: rgba(255,184,107,0.56); }
.task-badge { height: 30rpx; line-height: 30rpx; padding: 0 10rpx; border-radius: 999rpx; background: rgba(229,255,241,0.78); color: #16A779; font-size: 16rpx; font-weight: 900; white-space: nowrap; }
.sub-title { margin-top: 18rpx; color: #12342F; font-size: 27rpx; font-weight: 900; }
.sub-desc { margin-top: 7rpx; color: #7E9691; font-size: 21rpx; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dl-stat { margin-top: 18rpx; display: flex; gap: 10rpx; opacity: .72; }
.stat-card { flex: 1; padding: 12rpx 8rpx; border-radius: 22rpx; display: flex; flex-direction: column; align-items: center; background: rgba(255,255,255,0.42); border: 1px solid rgba(255,255,255,0.62); }
.stat-card text:first-child { color: #42635E; font-size: 26rpx; font-weight: 900; font-family: DIN, Arial, sans-serif; }
.stat-card text:last-child { color: #7E9691; font-size: 18rpx; margin-top: 2rpx; font-weight: 800; }
.reward-float { position: absolute; left: 50%; bottom: 160rpx; z-index: 30; transform: translateX(-50%); padding: 10rpx 20rpx; border-radius: 999rpx; background: rgba(255,255,255,0.9); color: #16A779; font-size: 24rpx; font-weight: 900; box-shadow: 0 14rpx 30rpx rgba(53,214,166,0.18); animation: rewardUp .8s ease-out forwards; pointer-events: none; }
.reward-float.pool { color: #F08322; }
.reward-float.hunt { color: #348FEA; }
@keyframes rewardUp {
0% { transform: translate3d(-50%, 16rpx, 0) scale(.86); opacity: 0; }
18% { opacity: 1; }
100% { transform: translate3d(-50%, -46rpx, 0) scale(1); opacity: 0; }
}
.ticket-fly { position: absolute; right: 96rpx; top: 330rpx; width: 70rpx; height: 70rpx; line-height: 70rpx; border-radius: 50%; text-align: center; background: linear-gradient(145deg, #FFF2B8, #FFB84D); color: #9A5A00; font-size: 34rpx; font-weight: 900; box-shadow: 0 14rpx 30rpx rgba(255,184,77,0.34); animation: ticketFly .9s cubic-bezier(.16,.84,.28,1) forwards; z-index: 20; }
@keyframes ticketFly {
0% { transform: translate3d(0, 0, 0) scale(.72) rotate(-8deg); opacity: 0; }
12% { transform: translate3d(-18rpx, -28rpx, 0) scale(1.08) rotate(6deg); opacity: 1; }
72% { opacity: 1; }
100% { transform: translate3d(-190rpx, -610rpx, 0) scale(.34) rotate(18deg); opacity: 0; }
}
</style>

26
package1/components/planet/planet-header.vue

@ -5,8 +5,8 @@
<view class="ph-title-row">
<text class="ph-title">Hello白嫖居民</text>
<view class="ph-actions">
<text class="ph-action" @tap="goTicketLog">明细</text>
<text class="ph-action ph-action-main" @tap="goDraw">开奖</text>
<text class="ph-action" @tap="goTicketLog">得券明细</text>
<text class="ph-action ph-action-main" @tap="goDraw">开奖记录</text>
</view>
</view>
<text class="ph-sub">攒券追捕开盲盒全校一起瓜分补给池</text>
@ -21,7 +21,7 @@
</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" @tap="goGuide">
<view class="ph-floating-box-lid"></view>
<text>白嫖说明书</text>
</view>
@ -74,7 +74,7 @@
<text class="ph-satellite-num">{{data.joinCount || 0}}</text>
<text class="ph-satellite-label">竟奖人数</text>
</view>
<view class="ph-satellite ph-satellite-right">
<view class="ph-satellite ph-satellite-right" @tap="goRank">
<text class="ph-satellite-num">{{rankText}}</text>
<text class="ph-satellite-label">财富坐标</text>
</view>
@ -138,6 +138,12 @@
goDraw() {
this.$emit('draw')
},
goGuide() {
this.$emit('guide')
},
goRank() {
this.$emit('rank')
},
pad(n) {
return n < 10 ? ('0' + n) : ('' + n)
},
@ -238,7 +244,7 @@
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;
opacity: 0.48;
z-index: 2;
}
@ -269,7 +275,6 @@
width: 170rpx;
height: 78rpx;
z-index: 4;
animation: stationFloat 5.6s ease-in-out infinite;
}
@keyframes stationFloat {
@ -307,7 +312,6 @@
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 {
@ -346,7 +350,6 @@
font-size: 23rpx;
font-weight: 900;
z-index: 5;
animation: treasureFloat 4.4s ease-in-out infinite;
}
.ph-floating-box-lid {
@ -404,7 +407,6 @@
width: 610rpx;
height: 610rpx;
z-index: 3;
animation: planetBreath 4.4s ease-in-out infinite;
}
.ph-planet-glow {
@ -416,7 +418,6 @@
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 {
@ -447,7 +448,6 @@
.ph-planet-map {
position: absolute;
background: rgba(53,214,166,0.16);
filter: blur(1rpx);
}
.ph-planet-map-a {
@ -482,7 +482,6 @@
position: absolute;
border-radius: 50%;
background: rgba(255,255,255,0.72);
filter: blur(2rpx);
}
.ph-shine-a {
@ -522,7 +521,6 @@
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;
@ -647,7 +645,6 @@
display: flex;
flex-direction: column;
align-items: center;
animation: orbitFloat 4s ease-in-out infinite;
}
.ph-satellite-left {
@ -692,7 +689,6 @@
width: 142rpx;
height: 164rpx;
z-index: 7;
animation: squirrelFloat 4.6s ease-in-out infinite;
}
@keyframes squirrelFloat {

1
package1/components/planet/planet-me.vue

@ -74,7 +74,6 @@
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); */
}

1
package1/components/planet/planet-rank.vue

@ -121,7 +121,6 @@
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 {

415
package1/planet/adventure.vue

@ -1,14 +1,14 @@
<template>
<view class="boost">
<view class="nav" :style="{paddingTop: statusBarHeight + 'px'}">
<view class="nav" :style="{height: navHeight + 'px', paddingTop: statusBarHeight + 'px'}">
<view class="nav-back" @tap="goBack"><text></text></view>
<view class="nav-title">学院助推赛</view>
</view>
<scroll-view scroll-y class="page" :style="{paddingTop: (statusBarHeight + 58) + 'px'}">
<scroll-view scroll-y class="page" :style="{paddingTop: (navHeight + 10) + 'px'}">
<view class="hero">
<view class="hero-kicker">COLLEGE ROCKET</view>
<view class="hero-title">今天为 {{collegeName}} 推一把</view>
<view class="hero-title">{{pageTitle}}</view>
<view class="college-picker" @tap="openCollegePicker">
<text>{{college ? '已选择学院' : '先选择学院'}}</text>
<text>{{collegeName}} </text>
@ -19,10 +19,28 @@
<view class="rocket-progress" :style="{width: rocketPercent + '%'}"></view>
</view>
</view>
<view class="hero-sub">每天1关通关贡献学院推进值21:30结算前三学院成员分别获得3/2/1张星球券</view>
<view class="hero-sub">{{heroSub}}</view>
</view>
<view class="rank-card">
<view class="glory-card">
<view class="section-head">
<text>今日最快通关榜</text>
<text>学院荣耀</text>
</view>
<view class="glory-list">
<view class="glory-item" v-for="(item,i) in gloryList" :key="item._key" :class="'rank-' + i">
<view class="glory-medal">{{['🥇','🥈','🥉'][i] || (i + 1)}}</view>
<view class="glory-user">
<text>{{item.college || '神秘学院'}}</text>
<text>{{item.nickname || '匿名同学'}}</text>
</view>
<view class="glory-time">{{item.durationSeconds || 0}}s</view>
</view>
</view>
<view class="empty" v-if="!gloryList.length">今天还没人通关第一枚金牌等你来拿</view>
</view>
<view class="rank-card" v-if="isDailyMode">
<view class="section-head">
<text>学院推进榜</text>
<text>我的学院第 {{home.myRankNo || '-'}} </text>
@ -40,16 +58,17 @@
<view class="game-card">
<view class="section-head">
<text>今日关卡</text>
<text>{{gameTitle}}</text>
<view class="timer-pill" :class="timerClass">
<text>{{cleared ? '已通关' : timerText}}</text>
</view>
</view>
<button class="arena-share" v-if="isPkMode" open-type="share">邀请同学来擂台</button>
<view class="start-strip" v-if="!playing && !cleared" @tap="startLevel">
<text>开始助推</text>
<text>先点这里再开始消除卡牌</text>
</view>
<view class="start-strip done" v-if="cleared">
<view class="start-strip done" v-if="cleared && isDailyMode">
<text>今日已助推</text>
<text>明天再来为学院继续推进</text>
</view>
@ -102,9 +121,9 @@
</view>
<view class="actions">
<view class="sub-btn" @tap="resetLevel">重开本关</view>
<view class="sub-btn" @tap="resetLevel">{{isDailyMode ? '重开本关' : '查看同局'}}</view>
<view class="main-btn" :class="{disabled: cleared || playing}" @tap="startLevel">
{{cleared ? '今日已助推' : (playing ? '助推中' : '开始助推')}}
{{startButtonText}}
</view>
</view>
</view>
@ -114,6 +133,8 @@
<view class="modal-card">
<view class="modal-title">{{modal.title}}</view>
<view class="modal-sub">{{modal.sub}}</view>
<view class="challenge-btn" v-if="modal.challenge" @tap="createChallenge">生成好友挑战卡</view>
<button class="challenge-share" v-if="shareChallenge" open-type="share">分享给好友挑战</button>
<view class="main-btn" @tap="closeModal">知道了</view>
</view>
</view>
@ -148,6 +169,7 @@
data() {
return {
statusBarHeight: 20,
navHeight: 64,
userId: '',
regionId: '',
nickname: '',
@ -167,7 +189,17 @@
timeLeft: 300,
timer: null,
roundSeed: '',
mode: 'daily',
roomId: '',
challengeId: '',
fixedSeed: '',
pkInfo: null,
challengeInfo: null,
shareChallenge: null,
gloryList: [],
moveCount: 0,
buildingLevel: false,
prebuildTimer: null,
modal: { show: false, title: '', sub: '' }
}
},
@ -175,6 +207,37 @@
collegeName() {
return this.college || '我的学院'
},
isDailyMode() {
return this.mode === 'daily'
},
isPkMode() {
return this.mode === 'pk'
},
isChallengeMode() {
return this.mode === 'challenge'
},
pageTitle() {
if (this.isPkMode) return '星球擂台开战'
if (this.isChallengeMode) return '好友挑战赛'
return `今天为 ${this.collegeName} 推一把`
},
heroSub() {
if (this.isPkMode) return '同一房间使用完全一致的卡牌布局。每人只有一次机会,退出或失败都会记录成绩。'
if (this.isChallengeMode) return '复刻好友通关布局,挑战同一组卡牌,结束后会显示领先或落后秒数。'
return '每天1关,通关贡献学院推进值。21:30结算,前三学院成员分别获得3/2/1张星球券。'
},
gameTitle() {
if (this.isPkMode) return '擂台关卡'
if (this.isChallengeMode) return '挑战关卡'
return '今日关卡'
},
startButtonText() {
if (this.playing) return '助推中'
if (this.cleared) return this.isDailyMode ? '今日已助推' : '成绩已提交'
if (this.isPkMode) return '开始擂台'
if (this.isChallengeMode) return '开始挑战'
return '开始助推'
},
collegeRanks() {
const list = this.home.rankList || []
let max = 1
@ -251,9 +314,16 @@
return '先看上层再下手'
}
},
onLoad() {
onLoad(options) {
const sys = uni.getSystemInfoSync()
this.statusBarHeight = sys.statusBarHeight || 20
this.initNavHeight()
options = options || {}
this.mode = options.mode || 'daily'
this.roomId = options.roomId || ''
this.challengeId = options.challengeId || ''
this.fixedSeed = options.seed ? decodeURIComponent(options.seed) : ''
if (!this.ensureLoginForShare()) return
this.userId = uni.getStorageSync('id') || ''
this.nickname = uni.getStorageSync('nickName') || uni.getStorageSync('nickname') || ''
this.avatar = uni.getStorageSync('avatarUrl') || uni.getStorageSync('avatar') || ''
@ -264,13 +334,20 @@
this.college = uni.getStorageSync('planetCollege_' + this.regionId) || ''
this.loadColleges()
this.loadHome()
this.buildLevel()
this.loadGlory()
this.prepareSharedMode()
this.schedulePrebuildLevel()
},
onUnload() {
this.clearTimer()
this.clearPrebuildTimer()
},
onHide() {
if (this.playing && this.isPkMode) {
this.submitLeave()
} else {
this.clearTimer()
}
},
onShow() {
if (!this.playing || !this.startTs) return
@ -282,8 +359,54 @@
this.startTimer(false)
}
},
onShareAppMessage() {
if (this.shareChallenge) {
return {
title: `我用${this.shareChallenge.durationSeconds}秒通关学院助推赛,你敢挑战吗?`,
path: '/package1/planet/adventure?mode=challenge&challengeId=' + this.shareChallenge.id
}
}
if (this.isPkMode && this.roomId) {
const roomName = (this.pkInfo && this.pkInfo.roomName) || '星球擂台'
return {
title: `星球擂台开战:${roomName}`,
path: '/package1/planet/adventure?mode=pk&roomId=' + this.roomId
}
}
return {
title: '学院助推赛,来帮学院冲榜',
path: '/package1/planet/adventure'
}
},
methods: {
initNavHeight() {
try {
const menu = uni.getMenuButtonBoundingClientRect && uni.getMenuButtonBoundingClientRect()
if (menu && menu.top && menu.height) {
this.navHeight = menu.top + menu.height + 8
return
}
} catch (e) {}
this.navHeight = this.statusBarHeight + 44
},
currentSharePath() {
if (this.isPkMode && this.roomId) return '/package1/planet/adventure?mode=pk&roomId=' + this.roomId
if (this.isChallengeMode && this.challengeId) return '/package1/planet/adventure?mode=challenge&challengeId=' + this.challengeId
return '/package1/planet/adventure'
},
ensureLoginForShare() {
if (this.userId || uni.getStorageSync('id')) return true
if (this.isPkMode || this.isChallengeMode) {
uni.setStorageSync('planetPendingSharePath', this.currentSharePath())
uni.redirectTo({
url: '/package2/login/login?redirect=planetPendingSharePath'
})
return false
}
return true
},
loadColleges() {
if (!this.regionId && !this.isDailyMode) return
this.tui.request('/app/planet/college/list', 'POST', {
regionId: this.regionId
}, false, false, true).then(res => {
@ -294,13 +417,17 @@
this.college = ''
uni.removeStorageSync('planetCollege_' + this.regionId)
}
if (!this.college && this.colleges.length) {
if (!this.college && this.colleges.length && this.isDailyMode) {
this.collegeModal = true
}
}
})
},
loadHome() {
if (!this.isDailyMode) {
this.cleared = false
return
}
this.tui.request('/app/planet/adventure/home', 'POST', {
userId: this.userId,
regionId: this.regionId,
@ -312,12 +439,86 @@
}
})
},
loadGlory() {
if (!this.regionId) return
this.tui.request('/app/planet/adventure/glory', 'POST', {
regionId: this.regionId
}, false, false, true).then(res => {
if (res.code == 200) {
this.gloryList = (res.result || []).map((item, index) => {
item._key = item.id || ('glory_' + index)
return item
})
}
})
},
prepareSharedMode() {
if (this.isPkMode && this.roomId && !this.fixedSeed) {
this.tui.request('/app/planet/adventure/pk/join', 'POST', {
userId: this.userId,
regionId: this.regionId,
nickname: this.nickname,
avatar: this.avatar,
college: this.college,
roomId: this.roomId
}).then(res => {
if (res.code != 200 || !res.result) {
this.tui.toast(res.message)
return
}
this.fixedSeed = res.result.seed
this.pkInfo = res.result.room
if (!this.regionId && this.pkInfo) this.regionId = this.pkInfo.regionId || ''
if (!this.college && res.result.player) this.college = res.result.player.college || ''
this.roundSeed = this.fixedSeed
this.buildLevel()
})
}
if (this.isChallengeMode && this.challengeId && !this.fixedSeed) {
this.tui.request('/app/planet/adventure/challenge/start', 'POST', {
userId: this.userId,
regionId: this.regionId,
challengeId: this.challengeId
}).then(res => {
if (res.code != 200 || !res.result) {
this.tui.toast(res.message)
return
}
this.fixedSeed = res.result.seed
this.challengeInfo = res.result.challenge
if (!this.regionId && this.challengeInfo) this.regionId = this.challengeInfo.regionId || ''
if (!this.college && this.challengeInfo) this.college = this.challengeInfo.college || ''
this.roundSeed = this.fixedSeed
this.buildLevel()
})
}
},
schedulePrebuildLevel() {
if (!this.isDailyMode && !this.fixedSeed) return
this.clearPrebuildTimer()
this.prebuildTimer = setTimeout(() => {
if (this.cards.length || this.playing || this.cleared) return
this.roundSeed = this.fixedSeed || this.newRoundSeed()
this.buildLevel()
if (!this.cards.length) this.buildLevel()
}, 200)
},
clearPrebuildTimer() {
if (!this.prebuildTimer) return
clearTimeout(this.prebuildTimer)
this.prebuildTimer = null
},
startLevel() {
if (this.cleared || this.playing) return
if (!this.college) {
this.clearPrebuildTimer()
if (!this.college && this.isDailyMode) {
this.openCollegePicker()
return
}
if (!this.isDailyMode) {
this.startFixedMode()
return
}
this.tui.request('/app/planet/adventure/start', 'POST', {
userId: this.userId,
regionId: this.regionId,
@ -332,17 +533,72 @@
this.session = res.result
this.playing = true
this.startTs = Date.now()
if (!this.cards.length) {
this.roundSeed = this.newRoundSeed()
this.buildLevel()
if (!this.cards.length) this.buildLevel()
}
this.startTimer()
})
},
startFixedMode() {
if (!this.fixedSeed && this.isPkMode) {
this.tui.request('/app/planet/adventure/pk/join', 'POST', {
userId: this.userId,
regionId: this.regionId,
nickname: this.nickname,
avatar: this.avatar,
college: this.college,
roomId: this.roomId
}).then(res => {
if (res.code != 200 || !res.result) {
this.tui.toast(res.message)
return
}
this.fixedSeed = res.result.seed
this.pkInfo = res.result.room
this.roomId = res.result.roomId || this.roomId
if (!this.regionId && this.pkInfo) this.regionId = this.pkInfo.regionId || ''
if (!this.college && res.result.player) this.college = res.result.player.college || ''
this.startFixedMode()
})
return
}
if (this.isChallengeMode && !this.fixedSeed) {
this.tui.request('/app/planet/adventure/challenge/start', 'POST', {
userId: this.userId,
regionId: this.regionId,
challengeId: this.challengeId
}).then(res => {
if (res.code != 200 || !res.result) {
this.tui.toast(res.message)
return
}
this.fixedSeed = res.result.seed
this.challengeInfo = res.result.challenge
this.challengeId = res.result.challengeId || this.challengeId
if (!this.regionId && this.challengeInfo) this.regionId = this.challengeInfo.regionId || ''
if (!this.college && this.challengeInfo) this.college = this.challengeInfo.college || ''
this.startFixedMode()
})
return
}
this.playing = true
this.startTs = Date.now()
this.roundSeed = this.fixedSeed
if (!this.cards.length) {
this.buildLevel()
if (!this.cards.length) this.buildLevel()
}
this.startTimer()
},
buildLevel() {
const icons = ['🍔', '🥤', '🥟', '🏀', '🎧', '🚲', '🍜', '🔥', '☕', '🍢']
const garbageIcons = ['🚀', '🍱', '🍗']
if (!this.roundSeed) this.roundSeed = this.newRoundSeed()
let cards = []
this.buildingLevel = true
try {
for (let attempt = 0; attempt < 100; attempt++) {
const seed = this.roundSeed + '_try_' + attempt
const positions = this.buildCardPositions(seed)
@ -366,6 +622,9 @@
this.slots = []
this.moveCount = 0
this.normalizeCards(icons)
} finally {
this.buildingLevel = false
}
this.refreshCardState()
},
newRoundSeed() {
@ -661,7 +920,7 @@
tightenOpeningPressure(cards, rand) {
let buryIndex = 0
for (let round = 0; round < 3; round++) {
this.refreshCardState()
this.forceRefreshCardState()
const visibleMap = {}
cards.forEach(card => {
if (card.removed || card.selected || card.coverDepth > 0 || this.isGarbageIcon(card.icon)) return
@ -683,7 +942,7 @@
})
if (!changed) break
}
this.refreshCardState()
this.forceRefreshCardState()
const visible = cards.filter(card => !card.removed && !card.selected && card.coverDepth === 0 && !this.isGarbageIcon(card.icon) && !card.openingSafe)
visible
.sort((a, b) => {
@ -694,7 +953,7 @@
.forEach(card => {
this.buryOpeningCard(card, cards, buryIndex++, rand)
})
this.refreshCardState()
this.forceRefreshCardState()
},
buryOpeningCard(card, cards, index, rand) {
card.layer = 0
@ -722,7 +981,7 @@
cover.y = card.y + (i === 0 ? 0 : (i === 1 ? 10 : -10)) + Math.floor(rand() * 4)
cover.style = `left:${cover.x}rpx;top:${cover.y}rpx;z-index:${this.cardZIndex(cover)};`
}
this.refreshCardState()
this.forceRefreshCardState()
},
repositionKeyCovers(cards, seed) {
const rand = this.seededRandom(seed + '_cover')
@ -840,6 +1099,10 @@
return icon
},
refreshCardState() {
if (this.buildingLevel) return
this.forceRefreshCardState()
},
forceRefreshCardState() {
this.cards.forEach(card => {
const depth = this.coverDepth(card)
card.locked = !card.removed && !card.selected && depth > 0
@ -950,6 +1213,10 @@
const progress = Math.max(100, 260 - duration + Math.max(0, 80 - this.moveCount))
this.playing = false
this.clearTimer()
if (!this.isDailyMode) {
this.submitCompetitive(true, duration, 0)
return
}
this.tui.request('/app/planet/adventure/submit', 'POST', {
userId: this.userId,
regionId: this.regionId,
@ -966,8 +1233,9 @@
}).then(res => {
if (res.code == 200) {
this.cleared = true
this.modal = { show: true, title: '助推成功', sub: `${this.collegeName} 获得 ${progress} 点推进值,晚上21:30争夺学院荣誉。` }
this.modal = { show: true, title: '助推成功', sub: `${this.collegeName} 获得 ${progress} 点推进值,晚上21:30争夺学院荣誉。`, challenge: true, duration }
this.loadHome()
this.loadGlory()
} else {
this.tui.toast(res.message)
}
@ -976,24 +1244,102 @@
failLevel(title, sub) {
this.playing = false
this.clearTimer()
if (!this.isDailyMode) {
this.submitCompetitive(false, Math.floor((Date.now() - this.startTs) / 1000), this.remainingCount)
return
}
this.modal = {
show: true,
title: title || '槽位满了',
sub: sub || '本关失败,不消耗次数。换个顺序再推一次。'
}
},
submitCompetitive(cleared, duration, remainingCards) {
const url = this.isPkMode ? '/app/planet/adventure/pk/submit' : '/app/planet/adventure/challenge/submit'
const data = {
userId: this.userId,
regionId: this.regionId,
nickname: this.nickname,
avatar: this.avatar,
college: this.college,
roomId: this.roomId,
challengeId: this.challengeId,
cleared: cleared ? 1 : 0,
durationSeconds: Math.max(0, duration || 0),
remainingSeconds: this.timeLeft,
remainingCards: remainingCards || this.remainingCount
}
this.tui.request(url, 'POST', data).then(res => {
if (res.code != 200) {
this.tui.toast(res.message)
return
}
if (this.isPkMode) {
this.cleared = true
this.modal = {
show: true,
title: cleared ? '擂台成绩已提交' : '擂台挑战失败',
sub: cleared ? `用时 ${duration} 秒,等待房间结算。` : '本房间只有一次机会,成绩已记录,等待最终排名。'
}
} else {
this.cleared = true
const result = res.result || {}
this.modal = {
show: true,
title: cleared ? '挑战完成' : '挑战失败',
sub: result.resultText || (cleared ? `用时 ${duration}` : '这次没追上,换个顺序还有机会。')
}
}
})
},
submitLeave() {
this.playing = false
this.clearTimer()
this.tui.request('/app/planet/adventure/pk/leave', 'POST', {
userId: this.userId,
regionId: this.regionId,
roomId: this.roomId,
remainingCards: this.remainingCount
}, false, false, true)
},
resetLevel() {
if (this.cleared) return
if (!this.isDailyMode && this.playing) {
this.tui.toast('擂台/挑战只有一次机会,不能重开')
return
}
this.playing = false
this.clearTimer()
this.timeLeft = this.timeLimit
this.roundSeed = this.newRoundSeed()
this.roundSeed = this.fixedSeed || this.newRoundSeed()
this.buildLevel()
if (!this.cards.length) this.buildLevel()
},
closeModal() {
this.modal.show = false
},
createChallenge() {
const duration = this.modal.duration || Math.max(1, Math.floor((Date.now() - this.startTs) / 1000))
this.tui.request('/app/planet/adventure/challenge/create', 'POST', {
userId: this.userId,
regionId: this.regionId,
nickname: this.nickname,
avatar: this.avatar,
college: this.college,
durationSeconds: duration
}).then(res => {
if (res.code != 200 || !res.result) {
this.tui.toast(res.message)
return
}
this.shareChallenge = {
id: res.result.id,
durationSeconds: duration
}
this.modal.sub = `我用 ${duration} 秒通关学院助推赛,你敢挑战吗?点击下方按钮分享给好友。`
this.modal.challenge = false
})
},
openCollegePicker() {
this.collegeModal = true
},
@ -1071,7 +1417,12 @@
return cards
},
goBack() {
uni.navigateBack()
const pages = getCurrentPages ? getCurrentPages() : []
if (pages.length > 1) {
uni.navigateBack({ delta: 1 })
return
}
uni.redirectTo({ url: '/package1/planet/index' })
}
}
}
@ -1079,11 +1430,12 @@
<style lang="scss" scoped>
.boost { min-height: 100vh; background: linear-gradient(155deg, #F3FFF4 0%, #EAF8FF 46%, #FFF7DE 100%); color: #12342F; }
.nav { position: fixed; top: 0; left: 0; right: 0; height: 44px; z-index: 200; display: flex; align-items: flex-end; justify-content: center; padding-bottom: 8rpx; background: rgba(243,255,244,0.86); }
.nav-back { position: absolute; left: 20rpx; bottom: 0; width: 70rpx; height: 44px; display: flex; align-items: center; justify-content: center; color: #12342F; font-size: 54rpx; }
.nav-title { color: #12342F; font-size: 34rpx; font-weight: 900; }
.nav { position: fixed; top: 0; left: 0; right: 0; z-index: 200; box-sizing: border-box; display: flex; align-items: center; justify-content: center; background: rgba(243,255,244,0.9); }
.nav-back { position: absolute; left: 24rpx; bottom: 12rpx; width: 56rpx; height: 56rpx; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.72); color: #12342F; box-shadow: 0 8rpx 20rpx rgba(18,52,47,.08); }
.nav-back text { font-size: 42rpx; line-height: 1; transform: translateY(-2rpx); }
.nav-title { padding-bottom: 14rpx; color: #12342F; font-size: 32rpx; font-weight: 900; }
.page { height: 100vh; box-sizing: border-box; padding-left: 24rpx; padding-right: 24rpx; }
.hero, .rank-card, .game-card { margin-bottom: 24rpx; border-radius: 42rpx; background: rgba(255,255,255,0.82); padding: 30rpx; box-shadow: 0 16rpx 42rpx rgba(79,183,255,0.10); }
.hero, .glory-card, .rank-card, .game-card { margin-bottom: 24rpx; border-radius: 42rpx; background: rgba(255,255,255,0.82); padding: 30rpx; box-shadow: 0 16rpx 42rpx rgba(79,183,255,0.10); }
.hero-kicker { color: #FF9C42; font-size: 22rpx; font-weight: 900; letter-spacing: 2rpx; }
.hero-title { margin-top: 10rpx; font-size: 42rpx; font-weight: 900; }
.hero-sub, .tips { margin-top: 16rpx; color: #6B817D; font-size: 24rpx; line-height: 1.55; }
@ -1114,9 +1466,22 @@
.rocket-progress { height: 100%; border-radius: 999rpx; background: linear-gradient(90deg, #35D6A6, #4FB7FF, #FFB84D); }
.section-head { display: flex; justify-content: space-between; align-items: center; font-size: 24rpx; color: #6B817D; }
.section-head text:first-child { color: #12342F; font-size: 31rpx; font-weight: 900; }
.glory-card { background: radial-gradient(circle at 90% 8%, rgba(255,184,77,.26), transparent 34%), linear-gradient(135deg, rgba(255,255,255,.92), rgba(242,250,255,.82)); }
.glory-list { margin-top: 18rpx; display: flex; flex-direction: column; gap: 14rpx; }
.glory-item { min-height: 86rpx; padding: 16rpx 18rpx; border-radius: 28rpx; background: rgba(255,255,255,.86); display: flex; align-items: center; gap: 16rpx; border: 2rpx solid rgba(255,255,255,.7); box-shadow: 0 12rpx 28rpx rgba(79,183,255,.08); }
.glory-item.rank-0 { background: linear-gradient(135deg, rgba(255,243,199,.96), rgba(255,255,255,.88)); box-shadow: 0 16rpx 34rpx rgba(255,184,77,.18); }
.glory-item.rank-1 { background: linear-gradient(135deg, rgba(241,245,249,.98), rgba(255,255,255,.88)); }
.glory-item.rank-2 { background: linear-gradient(135deg, rgba(255,235,213,.96), rgba(255,255,255,.88)); }
.glory-medal { width: 58rpx; height: 58rpx; line-height: 58rpx; border-radius: 50%; background: #fff; text-align: center; font-size: 32rpx; box-shadow: 0 8rpx 18rpx rgba(18,52,47,.08); }
.glory-user { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.glory-user text:first-child { color: #12342F; font-size: 27rpx; font-weight: 900; }
.glory-user text:last-child { margin-top: 6rpx; color: #6B817D; font-size: 22rpx; }
.glory-time { min-width: 90rpx; text-align: right; color: #FF9C42; font-size: 31rpx; font-weight: 900; }
.timer-pill { min-width: 126rpx; height: 48rpx; padding: 0 18rpx; border-radius: 999rpx; background: #EFFFF8; color: #20B486; display: flex; align-items: center; justify-content: center; font-size: 26rpx; font-weight: 900; box-shadow: 0 8rpx 20rpx rgba(32,180,134,0.12); }
.timer-pill.warning { background: #FFF4D7; color: #D88400; box-shadow: 0 8rpx 22rpx rgba(216,132,0,0.16); }
.timer-pill.danger { background: #FFE8E8; color: #F04444; box-shadow: 0 8rpx 24rpx rgba(240,68,68,0.2); }
.arena-share { margin: 18rpx 0 0; height: 64rpx; line-height: 64rpx; border-radius: 999rpx; background: linear-gradient(135deg, #7C3AED, #38BDF8); color: #fff; font-size: 24rpx; font-weight: 900; box-shadow: 0 12rpx 26rpx rgba(124,58,237,.16); }
.arena-share:after, .challenge-share:after { border: 0; }
.start-strip { margin-top: 20rpx; padding: 20rpx 24rpx; border-radius: 28rpx; background: linear-gradient(135deg, #35D6A6, #4FB7FF); color: #fff; display: flex; align-items: center; justify-content: space-between; box-shadow: 0 14rpx 34rpx rgba(53,214,166,0.2); }
.start-strip text:first-child { font-size: 30rpx; font-weight: 900; }
.start-strip text:last-child { font-size: 22rpx; opacity: .88; }
@ -1152,6 +1517,8 @@
.modal-card { width: 100%; border-radius: 42rpx; background: #fff; padding: 42rpx; text-align: center; }
.modal-title { font-size: 40rpx; font-weight: 900; }
.modal-sub { margin: 18rpx 0 30rpx; color: #6B817D; font-size: 26rpx; line-height: 1.55; }
.challenge-btn { margin-bottom: 18rpx; height: 76rpx; line-height: 76rpx; text-align: center; border-radius: 999rpx; background: linear-gradient(135deg, #7C3AED, #38BDF8); color: #fff; font-size: 27rpx; font-weight: 900; box-shadow: 0 14rpx 30rpx rgba(124,58,237,.18); }
.challenge-share { margin: 0 0 18rpx; height: 76rpx; line-height: 76rpx; border-radius: 999rpx; background: linear-gradient(135deg, #FF9C42, #FFD166); color: #fff; font-size: 27rpx; font-weight: 900; box-shadow: 0 14rpx 30rpx rgba(255,156,66,.18); }
.college-modal { text-align: left; }
.college-modal .modal-title, .college-modal .modal-sub { text-align: center; }
.college-list { max-height: 560rpx; margin-bottom: 24rpx; }

48
package1/planet/drawResult.vue

@ -1,12 +1,12 @@
<template>
<view class="dr" :style="{'--sb': statusBarHeight + 'px'}">
<view class="dr-bg"></view>
<view class="nav" :style="{paddingTop: statusBarHeight + 'px'}">
<view class="nav" :style="{height: navHeight + 'px', 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'}">
<scroll-view scroll-y class="dr-scroll" :style="{paddingTop: (navHeight + 10) + 'px'}">
<!-- 切换 -->
<view class="dr-tabs">
<view class="dr-tab" :class="{on: tab===0}" @tap="tab=0">最近开奖</view>
@ -61,6 +61,7 @@
data() {
return {
statusBarHeight: 20,
navHeight: 64,
tab: 0,
userId: '',
regionId: '',
@ -72,6 +73,7 @@
onLoad() {
const sys = uni.getSystemInfoSync()
this.statusBarHeight = sys.statusBarHeight || 20
this.initNavHeight()
this.userId = uni.getStorageSync('id') || ''
try {
const area = uni.getStorageSync('area')
@ -85,6 +87,16 @@
this.loadMyWinning()
},
methods: {
initNavHeight() {
try {
const menu = uni.getMenuButtonBoundingClientRect && uni.getMenuButtonBoundingClientRect()
if (menu && menu.top && menu.height) {
this.navHeight = menu.top + menu.height + 8
return
}
} catch (e) {}
this.navHeight = this.statusBarHeight + 44
},
loadResult() {
this.tui.request('/app/planet/draw/result', 'POST', {
userId: this.userId,
@ -116,7 +128,12 @@
})
},
goBack() {
const pages = getCurrentPages ? getCurrentPages() : []
if (pages.length > 1) {
uni.navigateBack({ delta: 1 })
return
}
uni.redirectTo({ url: '/package1/planet/index' })
}
}
}
@ -141,35 +158,40 @@
.nav {
position: fixed;
top: 0; left: 0; right: 0;
height: 44px;
z-index: 20;
box-sizing: border-box;
display: flex;
align-items: flex-end;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, rgba(243,255,244,0.9), rgba(243,255,244,0));
background: rgba(243,255,244,0.9);
}
.nav-back {
position: absolute;
left: 20rpx;
bottom: 0;
height: 44px;
width: 60rpx;
left: 24rpx;
bottom: 12rpx;
width: 56rpx;
height: 56rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255,255,255,.72);
box-shadow: 0 8rpx 20rpx rgba(18,52,47,.08);
}
.nav-back-icon {
color: #12342F;
font-size: 48rpx;
font-size: 42rpx;
line-height: 1;
transform: translateY(-2rpx);
}
.nav-title {
color: #12342F;
font-size: 34rpx;
font-weight: 800;
padding-bottom: 6rpx;
font-size: 32rpx;
font-weight: 900;
padding-bottom: 14rpx;
}
.dr-scroll {

369
package1/planet/index.vue

@ -15,14 +15,14 @@
<view class="bg-planet bg-planet-b"></view>
</view>
<view class="nav" :style="{paddingTop: statusBarHeight + 'px'}">
<view class="nav" :style="{height: navHeight + 'px', 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="planet-scroll" :style="{paddingTop: (statusBarHeight + 44) + 'px'}">
<scroll-view scroll-y enhanced :show-scrollbar="false" class="planet-scroll" :style="{paddingTop: (navHeight + 10) + 'px'}">
<!-- 骨架屏 -->
<view v-if="loading" class="skeleton">
<view class="sk-block sk-header"></view>
@ -35,20 +35,21 @@
<planet-header
:data="home"
@ticketlog="goTicketLog"
@draw="goDrawResult">
@draw="goDrawResult"
@guide="showGuideModal"
@rank="goRank">
</planet-header>
<planet-daily-loop
:data="home.dailyLoop"
:pool-amount="home.poolAmount"
:my-ticket-count="home.myTicketCount"
@collect="onDailyCollect"
@revenge="onDailyRevenge"
@more="goMore"
@join="onJoinPool">
</planet-daily-loop>
<planet-adventure-entry @start="goAdventure"></planet-adventure-entry>
<planet-news :list="home.newsList"></planet-news>
<planet-adventure-entry @start="goAdventure" @arena="goArena"></planet-adventure-entry>
<planet-me
:data="home"
@ -62,35 +63,6 @@
@open="openBox">
</planet-box>
<planet-operate
:data="home.operate"
@plant="onPlantTree"
@harvest="onHarvestTree"
@store="onStoreWarehouse"
@take="onTakeWarehouse"
@upgradeWarehouse="onUpgradeWarehouse"
@upgradeTower="onUpgradeTower"
@search="onRandomSearch"
@bid="onBidLandmark">
</planet-operate>
<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>
@ -113,19 +85,40 @@
<view class="box-result-btn" @tap="boxResult.show=false">收下了</view>
</view>
</view>
<view v-if="guideVisible" class="guide-mask" @tap="guideVisible=false">
<view class="guide-card" @tap.stop>
<view class="guide-kicker">BANJINLI GUIDE</view>
<view class="guide-title">白嫖星球玩法说明书</view>
<view class="guide-list">
<view class="guide-item">
<text>1</text>
<view>每天签到开补给箱玩学院助推赛都能获得星球券</view>
</view>
<view class="guide-item">
<text>2</text>
<view>把星球券投入奖池券越多开奖时瓜分现金奖励的权重越高</view>
</view>
<view class="guide-item">
<text>3</text>
<view>排行榜里可以发起星际追查有机会从榜上同学那里追回补给券</view>
</view>
<view class="guide-item">
<text>4</text>
<view>补给地图里有券树仓库防御塔地标和任务适合长期经营</view>
</view>
</view>
<view class="guide-btn" @tap="guideVisible=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'
import planetOperate from '@/package1/components/planet/planet-operate.vue'
import planetDailyLoop from '@/package1/components/planet/planet-daily-loop.vue'
import planetAdventureEntry from '@/package1/components/planet/planet-adventure-entry.vue'
@ -133,19 +126,15 @@
components: {
planetHeader,
planetMe,
planetTasks,
planetBox,
planetRank,
huntModal,
buffShop,
planetNews,
planetOperate,
planetDailyLoop,
planetAdventureEntry
},
data() {
return {
statusBarHeight: 20,
navHeight: 64,
loading: true,
userId: '',
regionId: '',
@ -171,6 +160,7 @@
show: false,
data: {}
},
guideVisible: false,
huntModal: {
show: false,
phase: 'searching',
@ -182,7 +172,7 @@
computed: {
stars() {
const arr = []
for (let n = 1; n <= 46; n++) {
for (let n = 1; n <= 20; n++) {
const top = (n * 29) % 100
const left = (n * 47) % 100
const delay = (n % 12) / 2
@ -195,6 +185,7 @@
onLoad() {
const sys = uni.getSystemInfoSync()
this.statusBarHeight = sys.statusBarHeight || 20
this.initNavHeight()
this.userId = uni.getStorageSync('id') || ''
this.nickname = uni.getStorageSync('nickName') || uni.getStorageSync('nickname') || ''
this.avatar = uni.getStorageSync('avatarUrl') || uni.getStorageSync('avatar') || ''
@ -207,6 +198,16 @@
this.loadHome()
},
methods: {
initNavHeight() {
try {
const menu = uni.getMenuButtonBoundingClientRect && uni.getMenuButtonBoundingClientRect()
if (menu && menu.top && menu.height) {
this.navHeight = menu.top + menu.height + 8
return
}
} catch (e) {}
this.navHeight = this.statusBarHeight + 44
},
loadHome(silent) {
if (!this.userId) {
this.tui.toast('请先登录')
@ -265,20 +266,6 @@
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('不能追捕自己')
@ -322,43 +309,6 @@
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)
})
})
},
promptTickets(title, callback) {
uni.showModal({
title,
editable: true,
placeholderText: '输入星球券数量',
success: (res) => {
if (!res.confirm) return
const tickets = parseInt(res.content || '0', 10)
if (!tickets || tickets <= 0) {
this.tui.toast('请输入正确数量')
return
}
callback(tickets)
}
})
},
operateRequest(url, data, successText) {
this.tui.request(url, 'POST', Object.assign({
userId: this.userId,
@ -368,38 +318,6 @@
if (res.code == 200) this.loadHome(true)
})
},
onPlantTree(config) {
this.promptTickets(`投入 ${config.cycleHours}h 券树`, (tickets) => {
this.operateRequest('/app/planet/tree/plant', { configId: config.id, tickets }, '种植成功')
})
},
onHarvestTree(order) {
if (order.status === 2) {
this.tui.toast('这棵券树已经收获')
return
}
this.operateRequest('/app/planet/tree/harvest', { orderId: order.id }, '收获成功')
},
onStoreWarehouse() {
this.promptTickets('存入松鼠仓库', (tickets) => {
this.operateRequest('/app/planet/warehouse/store', { tickets }, '存入成功')
})
},
onTakeWarehouse() {
this.promptTickets('从仓库取出', (tickets) => {
this.operateRequest('/app/planet/warehouse/take', { tickets }, '取出成功')
})
},
onUpgradeWarehouse() {
this.tui.modal('升级仓库', '确认消耗星球券升级松鼠仓库?', true, (ok) => {
if (ok) this.operateRequest('/app/planet/warehouse/upgrade', {}, '升级成功')
})
},
onUpgradeTower() {
this.tui.modal('升级防御塔', '确认消耗星球券提升拦截能力?', true, (ok) => {
if (ok) this.operateRequest('/app/planet/tower/upgrade', {}, '升级成功')
})
},
onRandomSearch() {
this.startSearch('/app/planet/search/random', {}, { nickname: '随机同校区玩家' })
},
@ -455,15 +373,30 @@
},
onJoinPool() {
const loop = this.home.dailyLoop || {}
const n = loop.suggestedAddTickets || 1
this.tui.modal('投入现金奖池', `建议投入 ${n} 张星球券,预计概率提升到 ${loop.suggestedProbability || 0}%。投入后星球券会被回收,确认上车?`, true, (ok) => {
if (!ok) return
this.operateRequest('/app/planet/pool/join', { tickets: n }, '投入成功')
}, '#22B889', '立即上车')
},
onBidLandmark(item) {
this.promptTickets(`争夺${item.name}`, (tickets) => {
this.operateRequest('/app/planet/landmark/bid', { landmarkId: item.id, tickets }, '投入成功')
if ((this.home.myTicketCount || 0) <= 0) {
this.tui.toast('星球券不足')
return
}
this.home.myTicketCount = Math.max(0, (this.home.myTicketCount || 0) - 1)
loop.myPoolTickets = (loop.myPoolTickets || 0) + 1
this.$set(this.home, 'dailyLoop', loop)
this.tui.request('/app/planet/pool/join', 'POST', {
userId: this.userId,
regionId: this.regionId,
tickets: 1
}).then((res) => {
if (res.code == 200) {
this.loadHome(true)
} else {
this.home.myTicketCount = (this.home.myTicketCount || 0) + 1
loop.myPoolTickets = Math.max(0, (loop.myPoolTickets || 0) - 1)
this.$set(this.home, 'dailyLoop', loop)
this.tui.toast(res.message)
}
}).catch(() => {
this.home.myTicketCount = (this.home.myTicketCount || 0) + 1
loop.myPoolTickets = Math.max(0, (loop.myPoolTickets || 0) - 1)
this.$set(this.home, 'dailyLoop', loop)
})
},
goDrawResult() {
@ -481,13 +414,26 @@
url: '/package1/planet/adventure'
})
},
goBack() {
uni.navigateBack({
delta: 1,
fail() {
uni.switchTab({ url: '/pages/index/index' })
}
goArena() {
uni.navigateTo({
url: '/package1/planet/pkHall'
})
},
goRank() {
uni.navigateTo({
url: '/package1/planet/rank'
})
},
goMore() {
uni.navigateTo({
url: '/package1/planet/more'
})
},
showGuideModal() {
this.guideVisible = true
},
goBack() {
uni.reLaunch({ url: '/pages/index/index' })
}
}
}
@ -505,11 +451,11 @@
}
.planet-bg {
position: fixed;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 1500rpx;
z-index: 0;
overflow: hidden;
pointer-events: none;
@ -518,9 +464,7 @@
.bg-aura {
position: absolute;
border-radius: 50%;
filter: blur(12rpx);
opacity: 0.72;
animation: auraFloat 8s ease-in-out infinite;
}
.bg-aura-a {
@ -558,7 +502,6 @@
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 {
@ -589,7 +532,7 @@
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;
opacity: 0.52;
}
.bg-shooting-a {
@ -646,7 +589,6 @@
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 {
@ -667,7 +609,6 @@
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 {
@ -676,7 +617,6 @@
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 {
@ -689,39 +629,42 @@
top: 0;
left: 0;
right: 0;
height: 44px;
z-index: 20;
box-sizing: border-box;
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));
background: rgba(243,255,244,0.9);
}
.nav-back {
position: absolute;
left: 20rpx;
bottom: 0;
height: 44px;
width: 60rpx;
left: 24rpx;
bottom: 12rpx;
width: 56rpx;
height: 56rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255,255,255,.72);
box-shadow: 0 8rpx 20rpx rgba(18,52,47,.08);
}
.nav-back-icon {
color: #12342F;
font-size: 48rpx;
font-size: 42rpx;
font-weight: 300;
line-height: 1;
transform: translateY(-2rpx);
}
.nav-title {
color: #12342F;
font-size: 34rpx;
font-weight: 800;
font-size: 32rpx;
font-weight: 900;
letter-spacing: 1rpx;
align-self: flex-end;
padding-bottom: 6rpx;
padding-bottom: 14rpx;
}
.planet-scroll {
@ -847,4 +790,98 @@
font-weight: 700;
box-shadow: 0 18rpx 36rpx rgba(53,214,166,0.25);
}
.guide-mask {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(18,52,47,0.32);
z-index: 70;
display: flex;
align-items: center;
justify-content: center;
padding: 0 36rpx;
}
.guide-card {
position: relative;
width: 100%;
padding: 44rpx 34rpx 34rpx;
border-radius: 46rpx;
background: linear-gradient(155deg, rgba(255,255,255,0.96), rgba(240,255,248,0.88));
border: 2rpx solid rgba(255,255,255,0.92);
box-shadow: 0 34rpx 80rpx rgba(53,214,166,0.24);
overflow: hidden;
}
.guide-card:before {
content: '';
position: absolute;
right: -100rpx;
top: -120rpx;
width: 320rpx;
height: 320rpx;
border-radius: 50%;
background: radial-gradient(circle, rgba(79,183,255,0.24), transparent 68%);
}
.guide-kicker {
position: relative;
color: #59CBB5;
font-size: 20rpx;
font-weight: 900;
letter-spacing: 3rpx;
}
.guide-title {
position: relative;
margin-top: 10rpx;
color: #12342F;
font-size: 40rpx;
font-weight: 900;
}
.guide-list {
position: relative;
margin-top: 26rpx;
}
.guide-item {
margin-top: 16rpx;
padding: 20rpx;
border-radius: 28rpx;
background: rgba(255,255,255,0.72);
display: flex;
gap: 16rpx;
color: #42635E;
font-size: 25rpx;
line-height: 1.45;
font-weight: 700;
}
.guide-item text {
width: 42rpx;
height: 42rpx;
line-height: 42rpx;
border-radius: 50%;
text-align: center;
background: linear-gradient(135deg, #35D6A6, #4FB7FF);
color: #FFFFFF;
font-size: 22rpx;
font-weight: 900;
flex-shrink: 0;
}
.guide-btn {
position: relative;
margin-top: 30rpx;
height: 82rpx;
line-height: 82rpx;
border-radius: 999rpx;
text-align: center;
background: linear-gradient(135deg, #35D6A6, #4FB7FF);
color: #FFFFFF;
font-size: 28rpx;
font-weight: 900;
box-shadow: 0 18rpx 36rpx rgba(53,214,166,0.24);
}
</style>

298
package1/planet/more.vue

@ -0,0 +1,298 @@
<template>
<view class="more" :style="{'--statusbar': statusBarHeight + 'px'}">
<view class="nav" :style="{paddingTop: statusBarHeight + 'px'}">
<view class="nav-back" @tap="goBack"><text></text></view>
<view class="nav-title">星球补给地图</view>
</view>
<scroll-view scroll-y class="page" :style="{paddingTop: (statusBarHeight + 58) + 'px'}">
<view v-if="loading" class="loading-card">正在加载星球补给...</view>
<block v-else>
<view class="hero">
<view>
<view class="hero-kicker">PLANET SUPPLY</view>
<view class="hero-title">把长期玩法都放在这里</view>
<view class="hero-sub">券树仓库防御塔地标任务和能量站想深入经营时再进来</view>
</view>
<view class="hero-ticket">
<text>{{home.myTicketCount || 0}}</text>
<text>星球券</text>
</view>
</view>
<planet-news :list="home.newsList"></planet-news>
<planet-operate
:data="home.operate"
@plant="onPlantTree"
@harvest="onHarvestTree"
@store="onStoreWarehouse"
@take="onTakeWarehouse"
@upgradeWarehouse="onUpgradeWarehouse"
@upgradeTower="onUpgradeTower"
@search="onRandomSearch"
@bid="onBidLandmark">
</planet-operate>
<planet-tasks
:tasks="home.tasks"
@claim="onClaimTask">
</planet-tasks>
<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>
</template>
<script>
import planetTasks from '@/package1/components/planet/planet-tasks.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'
import planetOperate from '@/package1/components/planet/planet-operate.vue'
export default {
components: {
planetTasks,
huntModal,
buffShop,
planetNews,
planetOperate
},
data() {
return {
statusBarHeight: 20,
loading: true,
userId: '',
regionId: '',
nickname: '',
avatar: '',
college: '',
home: {
myTicketCount: 0,
tasks: [],
buffShop: [],
newsList: [],
operate: {}
},
huntModal: {
show: false,
phase: 'searching',
result: null,
target: {}
}
}
},
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
})
},
onClaimTask(task) {
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)
})
},
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.operateRequest('/app/planet/buff/buy', { buffId: buff.id }, '购买成功')
})
},
promptTickets(title, callback) {
uni.showModal({
title,
editable: true,
placeholderText: '输入星球券数量',
success: (res) => {
if (!res.confirm) return
const tickets = parseInt(res.content || '0', 10)
if (!tickets || tickets <= 0) {
this.tui.toast('请输入正确数量')
return
}
callback(tickets)
}
})
},
operateRequest(url, data, successText) {
this.tui.request(url, 'POST', Object.assign({
userId: this.userId,
regionId: this.regionId
}, data || {})).then((res) => {
this.tui.toast(res.code == 200 ? successText : res.message, 1500, res.code == 200)
if (res.code == 200) this.loadHome(true)
})
},
onPlantTree(config) {
this.promptTickets(`投入 ${config.cycleHours}h 券树`, (tickets) => {
this.operateRequest('/app/planet/tree/plant', { configId: config.id, tickets }, '种植成功')
})
},
onHarvestTree(order) {
if (order.status === 2) {
this.tui.toast('这棵券树已经收获')
return
}
this.operateRequest('/app/planet/tree/harvest', { orderId: order.id }, '收获成功')
},
onStoreWarehouse() {
this.promptTickets('存入松鼠仓库', (tickets) => {
this.operateRequest('/app/planet/warehouse/store', { tickets }, '存入成功')
})
},
onTakeWarehouse() {
this.promptTickets('从仓库取出', (tickets) => {
this.operateRequest('/app/planet/warehouse/take', { tickets }, '取出成功')
})
},
onUpgradeWarehouse() {
this.tui.modal('升级仓库', '确认消耗星球券升级松鼠仓库?', true, (ok) => {
if (ok) this.operateRequest('/app/planet/warehouse/upgrade', {}, '升级成功')
})
},
onUpgradeTower() {
this.tui.modal('升级防御塔', '确认消耗星球券提升拦截能力?', true, (ok) => {
if (ok) this.operateRequest('/app/planet/tower/upgrade', {}, '升级成功')
})
},
onRandomSearch() {
this.startSearch('/app/planet/search/random', {}, { nickname: '随机同校区玩家' })
},
onBidLandmark(item) {
this.promptTickets(`争夺${item.name}`, (tickets) => {
this.operateRequest('/app/planet/landmark/bid', { landmarkId: item.id, tickets }, '投入成功')
})
},
startSearch(url, data, target) {
this.huntModal.show = true
this.huntModal.phase = 'searching'
this.huntModal.result = null
this.huntModal.target = target || { nickname: '同校区玩家' }
setTimeout(() => { this.huntModal.phase = 'locking' }, 900)
setTimeout(() => { this.huntModal.phase = 'chasing' }, 1800)
this.tui.request(url, 'POST', Object.assign({
userId: this.userId,
regionId: this.regionId
}, data || {}), false, false, true).then((res) => {
setTimeout(() => {
if (res.code == 200 && res.result) {
this.huntModal.result = {
result: res.result.intercepted ? 'shield' : 'success',
message: res.result.message,
gainTickets: res.result.gainTickets,
totalGain: res.result.gainTickets,
remainHunt: res.result.remainSearchCount
}
this.huntModal.phase = 'result'
this.loadHome(true)
} else {
this.huntModal.show = false
this.tui.toast(res.message)
}
}, 2200)
}).catch(() => {
this.huntModal.show = false
})
},
closeHunt() {
this.huntModal.show = false
this.huntModal.result = null
},
goBack() {
uni.navigateBack({
delta: 1,
fail() {
uni.navigateTo({ url: '/package1/planet/index' })
}
})
}
}
}
</script>
<style lang="scss" scoped>
.more {
min-height: 100vh;
background: linear-gradient(155deg, #F3FFF4 0%, #EAF8FF 46%, #FFF8DE 100%);
color: #12342F;
}
.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.96), 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 text { color: #12342F; font-size: 48rpx; font-weight: 300; }
.nav-title { color: #12342F; font-size: 34rpx; font-weight: 900; align-self: flex-end; padding-bottom: 6rpx; }
.page { height: 100vh; box-sizing: border-box; padding-left: 22rpx; padding-right: 22rpx; }
.loading-card { margin-top: 24rpx; height: 220rpx; border-radius: 38rpx; background: rgba(255,255,255,0.76); display: flex; align-items: center; justify-content: center; color: #6B817D; font-size: 26rpx; }
.hero { margin-top: 24rpx; padding: 32rpx; border-radius: 42rpx; background: linear-gradient(145deg, rgba(255,255,255,0.92), rgba(239,255,249,0.74)); border: 2rpx solid rgba(255,255,255,0.92); box-shadow: 0 22rpx 54rpx rgba(53,214,166,0.12); display: flex; justify-content: space-between; gap: 20rpx; }
.hero-kicker { color: #59CBB5; font-size: 20rpx; font-weight: 900; letter-spacing: 3rpx; }
.hero-title { margin-top: 8rpx; color: #12342F; font-size: 38rpx; font-weight: 900; }
.hero-sub { margin-top: 10rpx; color: #6B817D; font-size: 24rpx; line-height: 1.45; }
.hero-ticket { width: 140rpx; height: 120rpx; border-radius: 34rpx; background: linear-gradient(145deg, #35D6A6, #4FB7FF); color: #fff; display: flex; flex-direction: column; align-items: center; justify-content: center; flex-shrink: 0; }
.hero-ticket text:first-child { font-size: 36rpx; font-weight: 900; }
.hero-ticket text:last-child { margin-top: 4rpx; font-size: 20rpx; }
.bottom-space { height: 60rpx; }
</style>

306
package1/planet/pkHall.vue

@ -0,0 +1,306 @@
<template>
<view class="arena">
<view class="nav" :style="{height: navHeight + 'px', paddingTop: statusBarHeight + 'px'}">
<view class="nav-back" @tap="goBack"><text></text></view>
<view class="nav-title">星球擂台</view>
</view>
<scroll-view scroll-y class="page" :style="{paddingTop: (navHeight + 10) + 'px'}" @scrolltolower="loadMoreHotRooms">
<view class="hero">
<view class="hero-kicker">CAMPUS ARENA</view>
<view class="hero-title">同一关卡拼手速和决策</view>
<view class="hero-sub">独立于每日助推赛房间内所有人使用同一个 seed每人一次机会第一名通吃奖池</view>
<view class="create-btn" @tap="showCreate = true">创建房间</view>
</view>
<view class="section duo">
<view class="panel">
<view class="section-head"><text>我的房间</text></view>
<view class="mini-row" v-for="room in myRooms" :key="room._key" @tap="joinRoom(room)">
<text>{{room.roomName || '星球擂台'}}</text>
<text>{{roomStatus(room.status)}}</text>
<button class="mini-share" open-type="share" @tap.stop="setShareRoom(room)">分享</button>
</view>
<view class="empty small" v-if="!myRooms.length">暂无房间</view>
</view>
<view class="panel">
<view class="section-head"><text>我的战绩</text></view>
<view class="mini-row" v-for="record in myRecords" :key="record._key">
<text>{{record.cleared ? (record.durationSeconds + '秒通关') : '挑战失败'}}</text>
<text>{{record.rankNo ? ('第' + record.rankNo) : '待结算'}}</text>
</view>
<view class="empty small" v-if="!myRecords.length">暂无战绩</view>
</view>
</view>
<view class="section hot-section">
<view class="section-head">
<text>热门房间</text>
<text @tap="loadHall">刷新</text>
</view>
<view class="room-card" v-for="room in hotRooms" :key="room._key" @tap="joinRoom(room)">
<view class="room-main">
<view class="room-name">{{room.roomName || '星球擂台'}}</view>
<view class="room-meta">{{room.playerCount || 0}}/{{room.maxPlayers || 2}} · 入场 {{room.entryTickets || 1}} </view>
</view>
<view class="room-pool">
<text>{{room.poolTickets || 0}}</text>
<text>奖池</text>
</view>
<button class="share-mini" open-type="share" @tap.stop="setShareRoom(room)">邀请</button>
</view>
<view class="empty" v-if="!hotRooms.length">还没有公开擂台先开一间等同学来挑战</view>
<view class="load-more" v-if="hotRooms.length">{{hotLoadText}}</view>
</view>
</scroll-view>
<view class="modal" v-if="showCreate">
<view class="modal-card">
<view class="modal-title">创建星球擂台</view>
<input class="field" v-model="form.roomName" placeholder="房间名称" />
<input class="field" v-model.number="form.maxPlayers" type="number" placeholder="人数 2-5" />
<input class="field" v-model.number="form.tickets" type="number" placeholder="入场券数量" />
<input class="field" v-model="form.password" placeholder="私密房密码,不填则公开" />
<view class="modal-actions">
<view class="sub-btn" @tap="showCreate = false">取消</view>
<view class="main-btn" @tap="createRoom">创建</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
statusBarHeight: 20,
navHeight: 64,
userId: '',
regionId: '',
nickname: '',
avatar: '',
college: '',
hotRooms: [],
myRooms: [],
myRecords: [],
hotPageNum: 1,
hotPageSize: 10,
hotTotalPages: 1,
hotLoading: false,
showCreate: false,
shareRoom: null,
form: {
roomName: '今晚冲榜局',
maxPlayers: 2,
tickets: 1,
password: ''
}
}
},
computed: {
hotLoadText() {
if (this.hotLoading) return '正在加载更多房间...'
if (this.hotPageNum >= this.hotTotalPages) return '没有更多擂台了'
return '上滑加载更多擂台'
}
},
onLoad(options) {
const sys = uni.getSystemInfoSync()
this.statusBarHeight = sys.statusBarHeight || 20
this.initNavHeight()
options = options || {}
if (!uni.getStorageSync('id')) {
const path = options.roomId ? ('/package1/planet/pkHall?roomId=' + options.roomId) : '/package1/planet/pkHall'
uni.setStorageSync('planetPendingSharePath', path)
uni.redirectTo({
url: '/package2/login/login?redirect=planetPendingSharePath'
})
return
}
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.college = uni.getStorageSync('planetCollege_' + this.regionId) || ''
if (this.regionId) this.loadHall()
if (options.roomId) {
this.joinRoom({ id: options.roomId })
}
},
onShareAppMessage() {
const room = this.shareRoom || {}
const roomId = room.id || ''
return {
title: `星球擂台开战:${room.roomName || '同一关卡来PK'}`,
path: '/package1/planet/adventure?mode=pk&roomId=' + roomId
}
},
methods: {
initNavHeight() {
try {
const menu = uni.getMenuButtonBoundingClientRect && uni.getMenuButtonBoundingClientRect()
if (menu && menu.top && menu.height) {
this.navHeight = menu.top + menu.height + 8
return
}
} catch (e) {}
this.navHeight = this.statusBarHeight + 44
},
loadHall() {
this.hotPageNum = 1
this.hotTotalPages = 1
this.hotRooms = []
this.tui.request('/app/planet/adventure/pk/hall', 'POST', {
userId: this.userId,
regionId: this.regionId,
pageNumber: 1,
pageSize: this.hotPageSize
}, false, false, true).then(res => {
if (res.code == 200 && res.result) {
this.hotRooms = this.withKeys(res.result.hotRooms || [], 'hot_1')
this.hotPageNum = Number(res.result.hotPageNumber || 1)
this.hotTotalPages = Math.max(1, Number(res.result.hotTotalPages || 1))
this.myRooms = this.withKeys(res.result.myRooms || [], 'mine')
this.myRecords = this.withKeys(res.result.myRecords || [], 'record')
}
})
},
loadHotRooms(reset) {
if (this.hotLoading) return
if (!reset && this.hotPageNum >= this.hotTotalPages) return
const nextPage = reset ? 1 : this.hotPageNum + 1
this.hotLoading = true
this.tui.request('/app/planet/adventure/pk/hall', 'POST', {
userId: this.userId,
regionId: this.regionId,
pageNumber: nextPage,
pageSize: this.hotPageSize
}, false, false, true).then(res => {
this.hotLoading = false
if (res.code == 200 && res.result) {
const list = this.withKeys(res.result.hotRooms || [], 'hot_' + nextPage)
this.hotRooms = reset ? list : [...this.hotRooms, ...list]
this.hotPageNum = Number(res.result.hotPageNumber || nextPage)
this.hotTotalPages = Math.max(1, Number(res.result.hotTotalPages || 1))
}
}).catch(() => {
this.hotLoading = false
})
},
loadMoreHotRooms() {
this.loadHotRooms(false)
},
withKeys(list, prefix) {
return list.map((item, index) => {
item.password = ''
item._key = item.id || (prefix + '_' + index)
return item
})
},
setShareRoom(room) {
this.shareRoom = room
},
createRoom() {
this.tui.request('/app/planet/adventure/pk/create', 'POST', {
userId: this.userId,
regionId: this.regionId,
nickname: this.nickname,
avatar: this.avatar,
college: this.college,
roomName: this.form.roomName,
maxPlayers: this.form.maxPlayers,
publicFlag: this.form.password ? 0 : 1,
password: this.form.password,
tickets: this.form.tickets
}).then(res => {
if (res.code != 200 || !res.result) {
this.tui.toast(res.message)
return
}
this.showCreate = false
this.loadHall()
this.joinRoom(res.result)
})
},
joinRoom(room) {
this.tui.request('/app/planet/adventure/pk/join', 'POST', {
userId: this.userId,
regionId: this.regionId,
nickname: this.nickname,
avatar: this.avatar,
college: this.college,
roomId: room.id,
password: room.password || ''
}).then(res => {
if (res.code != 200 || !res.result) {
this.tui.toast(res.message)
return
}
uni.navigateTo({
url: '/package1/planet/adventure?mode=pk&roomId=' + room.id + '&seed=' + encodeURIComponent(res.result.seed || '')
})
})
},
roomStatus(status) {
if (status === 2) return '已结算'
if (status === 1) return '进行中'
if (status === 3) return '已取消'
return '等待中'
},
goBack() {
const pages = getCurrentPages ? getCurrentPages() : []
if (pages.length > 1) {
uni.navigateBack({ delta: 1 })
return
}
uni.redirectTo({ url: '/package1/planet/index' })
}
}
}
</script>
<style lang="scss" scoped>
.arena { min-height: 100vh; background: linear-gradient(155deg, #F7F2FF 0%, #EAF8FF 46%, #FFF7DE 100%); color: #172033; }
.nav { position: fixed; top: 0; left: 0; right: 0; z-index: 20; box-sizing: border-box; display: flex; align-items: center; justify-content: center; background: rgba(247,242,255,.9); }
.nav-back { position: absolute; left: 24rpx; bottom: 12rpx; width: 56rpx; height: 56rpx; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.72); color: #172033; box-shadow: 0 8rpx 20rpx rgba(23,32,51,.08); }
.nav-back text { font-size: 42rpx; line-height: 1; transform: translateY(-2rpx); }
.nav-title { padding-bottom: 14rpx; font-size: 32rpx; font-weight: 900; }
.page { height: 100vh; box-sizing: border-box; padding-left: 24rpx; padding-right: 24rpx; }
.hero, .section, .panel { margin-bottom: 24rpx; border-radius: 42rpx; background: rgba(255,255,255,.84); padding: 30rpx; box-shadow: 0 18rpx 48rpx rgba(124,58,237,.10); }
.hot-section { margin-bottom: 46rpx; }
.hero { background: radial-gradient(circle at 90% 10%, rgba(124,58,237,.22), transparent 36%), linear-gradient(135deg, rgba(255,255,255,.96), rgba(232,246,255,.78)); }
.hero-kicker { color: #7C3AED; font-size: 22rpx; font-weight: 900; letter-spacing: 2rpx; }
.hero-title { margin-top: 10rpx; font-size: 42rpx; font-weight: 900; }
.hero-sub { margin-top: 14rpx; color: #667085; font-size: 24rpx; line-height: 1.55; }
.create-btn, .main-btn { margin-top: 22rpx; height: 76rpx; line-height: 76rpx; border-radius: 999rpx; text-align: center; color: #fff; font-size: 28rpx; font-weight: 900; background: linear-gradient(135deg, #7C3AED, #38BDF8); box-shadow: 0 16rpx 34rpx rgba(124,58,237,.18); }
.section-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18rpx; color: #7C3AED; font-size: 23rpx; font-weight: 900; }
.section-head text:first-child { color: #172033; font-size: 31rpx; }
.room-card { margin-top: 16rpx; padding: 22rpx; border-radius: 30rpx; background: linear-gradient(135deg, rgba(255,255,255,.92), rgba(238,247,255,.82)); display: flex; align-items: center; justify-content: space-between; border: 2rpx solid rgba(124,58,237,.10); }
.room-main { flex: 1; min-width: 0; }
.room-name { font-size: 29rpx; font-weight: 900; }
.room-meta { margin-top: 8rpx; color: #667085; font-size: 22rpx; }
.room-pool { min-width: 108rpx; height: 88rpx; border-radius: 26rpx; background: #FFF3D7; color: #B7791F; display: flex; flex-direction: column; align-items: center; justify-content: center; font-weight: 900; }
.room-pool text:first-child { font-size: 32rpx; }
.room-pool text:last-child { font-size: 19rpx; margin-top: 4rpx; }
.share-mini { margin: 0 0 0 14rpx; padding: 0 18rpx; min-width: 0; height: 56rpx; line-height: 56rpx; border-radius: 999rpx; background: #EEF2FF; color: #7C3AED; font-size: 22rpx; font-weight: 900; }
.share-mini:after, .mini-share:after { border: 0; }
.duo { display: flex; gap: 18rpx; background: transparent; box-shadow: none; padding: 0; }
.panel { flex: 1; min-width: 0; margin-bottom: 0; padding: 22rpx; border-radius: 34rpx; }
.mini-row { margin-top: 14rpx; padding: 16rpx; border-radius: 22rpx; background: rgba(248,250,252,.9); display: flex; justify-content: space-between; gap: 12rpx; font-size: 22rpx; color: #667085; }
.mini-row text:first-child { color: #172033; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mini-share { margin: 0; padding: 0 14rpx; min-width: 0; height: 40rpx; line-height: 40rpx; border-radius: 999rpx; background: #F4F3FF; color: #7C3AED; font-size: 18rpx; font-weight: 900; }
.empty { margin-top: 20rpx; color: #8A94A6; font-size: 24rpx; }
.empty.small { font-size: 21rpx; }
.load-more { margin-top: 24rpx; height: 58rpx; line-height: 58rpx; text-align: center; border-radius: 999rpx; background: rgba(238,242,255,.76); color: #7C3AED; font-size: 23rpx; font-weight: 900; }
.modal { position: fixed; inset: 0; z-index: 99; background: rgba(23,32,51,.22); display: flex; align-items: center; justify-content: center; padding: 46rpx; }
.modal-card { width: 100%; border-radius: 42rpx; background: #fff; padding: 36rpx; }
.modal-title { text-align: center; font-size: 36rpx; font-weight: 900; margin-bottom: 22rpx; }
.field { height: 78rpx; margin-bottom: 16rpx; padding: 0 22rpx; border-radius: 22rpx; background: #F5F7FB; font-size: 25rpx; }
.modal-actions { display: flex; gap: 16rpx; margin-top: 10rpx; }
.sub-btn, .main-btn { flex: 1; margin-top: 0; height: 76rpx; line-height: 76rpx; border-radius: 999rpx; text-align: center; font-size: 27rpx; font-weight: 900; }
.sub-btn { background: #F2F4F7; color: #667085; }
</style>

317
package1/planet/rank.vue

@ -0,0 +1,317 @@
<template>
<view class="rank-page" :style="{'--statusbar': statusBarHeight + 'px'}">
<view class="nav" :style="{paddingTop: statusBarHeight + 'px'}">
<view class="nav-back" @tap="goBack"><text></text></view>
<view class="nav-title">星球排行榜</view>
</view>
<scroll-view scroll-y enhanced :show-scrollbar="false" class="page" :style="{paddingTop: (statusBarHeight + 58) + 'px'}" @scrolltolower="loadMore">
<view v-if="loading" class="loading-card">正在扫描财富坐标...</view>
<block v-else>
<view class="radar-card">
<view class="radar-visual">
<view class="radar-sweep"></view>
<view class="radar-ring ring-a"></view>
<view class="radar-ring ring-b"></view>
<view class="radar-dot"></view>
</view>
<view class="radar-copy">
<view class="radar-kicker">SCHOOL RICH LIST</view>
<view class="radar-title">全校首富雷达</view>
<view class="radar-sub">从榜单里选定目标发起星际追查抢回今日补给权</view>
</view>
<view class="radar-count">
<text>{{home.remainHunt || 0}}</text>
<text>次追查</text>
</view>
</view>
<view class="rank-head">
<view>
<view class="rank-kicker">WEALTH COORDINATES</view>
<view class="rank-title">财富坐标榜</view>
</view>
<view class="rank-page-no">已加载 {{pageNum}} / {{totalPages}} </view>
</view>
<view v-if="pagedList.length" class="rank-list">
<view
class="rank-row"
v-for="(item, index) in pagedList"
:key="item._rankKey">
<view class="rank-no">#{{item._displayRankNo}}</view>
<image class="avatar" :class="{stealth: item.stealth}" :src="item.stealth ? defaultAvatar : (item.avatar || defaultAvatar)" mode="aspectFill"></image>
<view class="user-main">
<view class="user-name">
<text>{{item.stealth ? '隐身侠' : (item.nickname || '神秘同学')}}</text>
<text v-if="item.stealth" class="stealth-tag">隐身</text>
<text v-if="item.self" class="me-tag">ME</text>
</view>
<view class="user-meta">
<text>{{item.ticketCount || 0}} 张星球券</text>
<text v-if="!item.stealth && item.rankKeepDays > 0">霸榜 {{item.rankKeepDays}} </text>
</view>
</view>
<view
class="hunt-btn"
:class="{disabled: item.self || item.stealth || item.shielded || (home.remainHunt || 0) <= 0}"
@tap="onHunt(item)">
{{huntText(item)}}
</view>
</view>
</view>
<view v-else class="empty-card">暂无上榜居民攒券登顶成为今日主角</view>
<view v-if="rankList.length" class="load-more">{{loadMoreText}}</view>
<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>
</template>
<script>
import huntModal from '@/package1/components/planet/hunt-modal.vue'
export default {
components: {
huntModal
},
data() {
return {
statusBarHeight: 20,
loading: true,
userId: '',
regionId: '',
nickname: '',
avatar: '',
college: '',
pageNum: 1,
pageSize: 10,
rankRows: [],
listLoading: false,
noMore: false,
defaultAvatar: 'https://jewel-shop.oss-cn-beijing.aliyuncs.com/41cfb56caff4419b94b69d0f2303b602.png',
home: {
remainHunt: 0,
rankList: []
},
huntModal: {
show: false,
phase: 'searching',
result: null,
target: {}
},
huntTimers: []
}
},
computed: {
rankList() {
return (this.rankRows || []).map((item, index) => {
return Object.assign({}, item, {
_rankKey: String(item.userId || item.rankNo || index),
_displayRankNo: item.rankNo || (index + 1)
})
})
},
totalPages() {
return Math.max(1, Number(this.home.rankTotalPages || 1))
},
pagedList() {
return this.rankList
},
loadMoreText() {
if (this.listLoading) return '正在加载更多坐标...'
if (this.noMore) return '没有更多财富坐标了'
return '上滑加载更多坐标'
}
},
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(true)
},
onUnload() {
this.clearHuntTimers()
},
methods: {
loadHome(reset) {
if (this.listLoading) return
if (!this.userId) {
this.tui.toast('请先登录')
return
}
if (!this.regionId) {
this.loading = false
this.tui.toast('未获取到校区信息')
return
}
if (reset) {
this.pageNum = 1
this.noMore = false
this.rankRows = []
}
if (reset) this.loading = true
this.listLoading = true
this.tui.request('/app/planet/home', 'POST', {
userId: this.userId,
regionId: this.regionId,
nickname: this.nickname,
avatar: this.avatar,
college: this.college,
pageNumber: this.pageNum,
pageSize: this.pageSize
}, false, false, true).then((res) => {
this.loading = false
this.listLoading = false
if (res.code == 200 && res.result) {
this.home = res.result
this.pageNum = Number(res.result.rankPageNumber || this.pageNum)
if (this.pageNum > this.totalPages) this.pageNum = this.totalPages
const records = res.result.rankList || []
this.rankRows = reset ? records : this.rankRows.concat(records)
this.noMore = this.pageNum >= this.totalPages || records.length < this.pageSize
} else if (res.message) {
this.tui.toast(res.message)
}
}).catch(() => {
this.loading = false
this.listLoading = false
})
},
loadMore() {
if (this.listLoading || this.noMore) return
if (this.pageNum >= this.totalPages) {
this.noMore = true
return
}
this.pageNum += 1
this.loadHome(false)
},
huntText(item) {
if (item.self) return '榜上有我'
if (item.stealth) return '已隐身'
if (item.shielded) return '防护中'
if ((this.home.remainHunt || 0) <= 0) return '次数用完'
return '发起追查'
},
onHunt(item) {
if (item.self) {
this.tui.toast('不能追捕自己')
return
}
if (item.stealth) {
this.tui.toast('目标正在隐身,暂时无法追查')
return
}
if (item.shielded) {
this.tui.toast('目标已开启防护罩')
return
}
if ((this.home.remainHunt || 0) <= 0) {
this.tui.toast('今日追捕次数已用完')
return
}
this.clearHuntTimers()
this.huntModal.show = true
this.huntModal.phase = 'searching'
this.huntModal.result = null
this.huntModal.target = item
this.huntTimers.push(setTimeout(() => { this.huntModal.phase = 'locking' }, 900))
this.huntTimers.push(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) => {
this.huntTimers.push(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
})
},
clearHuntTimers() {
this.huntTimers.forEach((timer) => clearTimeout(timer))
this.huntTimers = []
},
closeHunt() {
this.huntModal.show = false
this.huntModal.result = null
},
goBack() {
uni.navigateBack({
delta: 1,
fail() {
uni.navigateTo({ url: '/package1/planet/index' })
}
})
}
}
}
</script>
<style lang="scss" scoped>
.rank-page { min-height: 100vh; background: linear-gradient(155deg, #F3FFF4 0%, #EAF8FF 46%, #FFF7DD 100%); color: #12342F; }
.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.98), 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 text { color: #12342F; font-size: 48rpx; font-weight: 300; }
.nav-title { color: #12342F; font-size: 34rpx; font-weight: 900; align-self: flex-end; padding-bottom: 6rpx; }
.page { height: 100vh; box-sizing: border-box; padding-left: 22rpx; padding-right: 22rpx; }
.loading-card, .empty-card { margin-top: 24rpx; height: 220rpx; border-radius: 38rpx; background: rgba(255,255,255,0.76); display: flex; align-items: center; justify-content: center; color: #6B817D; font-size: 26rpx; }
.radar-card { position: relative; margin-top: 24rpx; min-height: 210rpx; padding: 30rpx 24rpx; border-radius: 46rpx; background: radial-gradient(circle at 18% 50%, rgba(255,122,89,0.16), transparent 34%), linear-gradient(135deg, rgba(255,255,255,0.9), rgba(255,246,219,0.7)); border: 2rpx solid rgba(255,255,255,0.94); box-shadow: 0 24rpx 58rpx rgba(255,122,89,0.12); display: flex; align-items: center; overflow: hidden; }
.radar-visual { position: relative; width: 138rpx; height: 138rpx; border-radius: 50%; border: 2rpx solid rgba(255,122,89,0.22); background: radial-gradient(circle, rgba(255,122,89,0.13), rgba(255,255,255,0.48)); flex-shrink: 0; overflow: hidden; }
.radar-ring { position: absolute; border-radius: 50%; border: 1rpx solid rgba(255,122,89,0.22); }
.ring-a { left: 24rpx; top: 24rpx; width: 88rpx; height: 88rpx; }
.ring-b { left: 48rpx; top: 48rpx; width: 40rpx; height: 40rpx; }
.radar-sweep { position: absolute; left: 50%; top: 50%; width: 64rpx; height: 5rpx; border-radius: 999rpx; transform-origin: left center; background: linear-gradient(90deg, rgba(255,122,89,0.76), rgba(255,122,89,0)); animation: sweep 1.8s linear infinite; }
.radar-dot { position: absolute; right: 30rpx; top: 38rpx; width: 16rpx; height: 16rpx; border-radius: 50%; background: #FF7A59; box-shadow: 0 0 18rpx rgba(255,122,89,0.55); }
@keyframes sweep { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.radar-copy { flex: 1; min-width: 0; margin-left: 22rpx; }
.radar-kicker, .rank-kicker { color: #FF7A59; font-size: 18rpx; font-weight: 900; letter-spacing: 3rpx; }
.radar-title { margin-top: 6rpx; color: #12342F; font-size: 38rpx; font-weight: 900; }
.radar-sub { margin-top: 8rpx; color: #7E9691; font-size: 23rpx; line-height: 1.42; font-weight: 600; }
.radar-count { width: 112rpx; height: 112rpx; border-radius: 34rpx; background: linear-gradient(135deg, #FF7A59, #FFB84D); color: #FFFFFF; display: flex; flex-direction: column; align-items: center; justify-content: center; box-shadow: 0 12rpx 26rpx rgba(255,122,89,0.18); transform: rotate(4deg); flex-shrink: 0; }
.radar-count text:first-child { font-size: 40rpx; font-weight: 900; line-height: 42rpx; }
.radar-count text:last-child { font-size: 19rpx; font-weight: 800; margin-top: 4rpx; }
.rank-head { margin-top: 30rpx; display: flex; align-items: flex-end; justify-content: space-between; }
.rank-title { margin-top: 6rpx; color: #12342F; font-size: 40rpx; font-weight: 900; }
.rank-page-no { color: #6B817D; font-size: 23rpx; font-weight: 800; }
.rank-list { margin-top: 18rpx; }
.rank-row { margin-top: 16rpx; padding: 22rpx; border-radius: 34rpx; background: rgba(255,255,255,0.82); border: 2rpx solid rgba(255,255,255,0.94); box-shadow: 0 16rpx 36rpx rgba(53,214,166,0.1); display: flex; align-items: center; }
.rank-no { min-width: 70rpx; color: #22B889; font-size: 28rpx; font-weight: 900; }
.avatar { width: 86rpx; height: 86rpx; border-radius: 28rpx; border: 4rpx solid rgba(255,255,255,0.94); box-shadow: 0 12rpx 24rpx rgba(18,52,47,0.12); flex-shrink: 0; }
.avatar.stealth { opacity: .58; filter: grayscale(100%); }
.user-main { flex: 1; min-width: 0; margin-left: 18rpx; }
.user-name { display: flex; align-items: center; color: #12342F; font-size: 28rpx; font-weight: 900; }
.user-name text:first-child { max-width: 220rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.me-tag { margin-left: 10rpx; padding: 4rpx 10rpx; border-radius: 999rpx; background: linear-gradient(135deg, #35D6A6, #4FB7FF); color: #FFFFFF; font-size: 18rpx; }
.stealth-tag { margin-left: 10rpx; padding: 4rpx 10rpx; border-radius: 999rpx; background: #EEF2FF; color: #7C3AED; font-size: 18rpx; }
.user-meta { margin-top: 8rpx; display: flex; flex-wrap: wrap; gap: 10rpx; color: #6B817D; font-size: 22rpx; font-weight: 700; }
.hunt-btn { width: 132rpx; height: 62rpx; line-height: 62rpx; border-radius: 999rpx; text-align: center; background: linear-gradient(135deg, #FF7A59, #FFB84D); color: #FFFFFF; font-size: 22rpx; font-weight: 900; box-shadow: 0 14rpx 28rpx rgba(255,122,89,0.2); flex-shrink: 0; }
.hunt-btn.disabled { background: rgba(18,52,47,0.08); color: #9AA9A5; box-shadow: none; }
.load-more { margin-top: 28rpx; height: 66rpx; line-height: 66rpx; text-align: center; border-radius: 999rpx; background: rgba(255,255,255,0.72); color: #22B889; font-size: 24rpx; font-weight: 900; box-shadow: 0 12rpx 26rpx rgba(53,214,166,0.1); }
.bottom-space { height: 70rpx; }
</style>

46
package1/planet/ticketLog.vue

@ -1,12 +1,12 @@
<template>
<view class="tl" :style="{'--sb': statusBarHeight + 'px'}">
<view class="tl-bg"></view>
<view class="nav" :style="{paddingTop: statusBarHeight + 'px'}">
<view class="nav" :style="{height: navHeight + 'px', 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'}"
<scroll-view scroll-y class="tl-scroll" :style="{paddingTop: (navHeight + 10) + 'px'}"
@scrolltolower="loadMore">
<!-- 汇总卡片 -->
<view class="tl-sum">
@ -64,6 +64,7 @@
data() {
return {
statusBarHeight: 20,
navHeight: 64,
userId: '',
regionId: '',
balance: 0,
@ -78,6 +79,7 @@
onLoad() {
const sys = uni.getSystemInfoSync()
this.statusBarHeight = sys.statusBarHeight || 20
this.initNavHeight()
this.userId = uni.getStorageSync('id') || ''
try {
const area = uni.getStorageSync('area')
@ -86,6 +88,16 @@
this.loadPage(true)
},
methods: {
initNavHeight() {
try {
const menu = uni.getMenuButtonBoundingClientRect && uni.getMenuButtonBoundingClientRect()
if (menu && menu.top && menu.height) {
this.navHeight = menu.top + menu.height + 8
return
}
} catch (e) {}
this.navHeight = this.statusBarHeight + 44
},
loadPage(reset) {
if (this.loading) return
if (!this.userId) {
@ -142,7 +154,12 @@
return map[type] || '星球券变动'
},
goBack() {
const pages = getCurrentPages ? getCurrentPages() : []
if (pages.length > 1) {
uni.navigateBack({ delta: 1 })
return
}
uni.redirectTo({ url: '/package1/planet/index' })
}
}
}
@ -167,33 +184,36 @@
.nav {
position: fixed;
top: 0; left: 0; right: 0;
height: 44px;
z-index: 20;
box-sizing: border-box;
display: flex;
align-items: flex-end;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, rgba(243,255,244,0.9), rgba(243,255,244,0));
background: rgba(243,255,244,0.9);
}
.nav-back {
position: absolute;
left: 20rpx;
bottom: 0;
height: 44px;
width: 60rpx;
left: 24rpx;
bottom: 12rpx;
width: 56rpx;
height: 56rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255,255,255,.72);
box-shadow: 0 8rpx 20rpx rgba(18,52,47,.08);
}
.nav-back-icon { color: #12342F; font-size: 48rpx; font-weight: 300; }
.nav-back-icon { color: #12342F; font-size: 42rpx; font-weight: 300; line-height: 1; transform: translateY(-2rpx); }
.nav-title {
color: #12342F;
font-size: 34rpx;
font-weight: 800;
font-size: 32rpx;
font-weight: 900;
letter-spacing: 1rpx;
padding-bottom: 6rpx;
padding-bottom: 14rpx;
}
.tl-scroll {

Loading…
Cancel
Save