You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

250 lines
5.1 KiB

<template>
<view class="pt">
<view class="pt-head">
<view>
<text class="pt-kicker">SUPPLY MAP</text>
<text class="pt-title">星球补给地图</text>
</view>
<text class="pt-sub">完成校园行动点亮补给点</text>
</view>
<view class="pt-list">
<view class="pt-item" v-for="(t, i) in taskCards" :key="i" :class="t.cardClass">
<view class="pt-route-dot"></view>
<view class="pt-item-icon">{{t.icon}}</view>
<view class="pt-item-mid">
<view class="pt-item-name">{{t.name}}</view>
<view class="pt-item-desc">{{t.description}}</view>
</view>
<view class="pt-item-btn"
:class="{auto: t.actionType==='auto', done: t.actionType==='claim' && !t.canClaim}"
@tap="onClick(t)">
<text>+{{t.rewardTickets}}</text>
<text>{{btnText(t)}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
tasks: {
type: Array,
default: () => []
}
},
computed: {
taskCards() {
return (this.tasks || []).map((item, index) => {
return Object.assign({}, item, {
icon: this.taskEmoji(item.code),
cardClass: this.taskClass(item.code) + (index % 2 === 1 ? ' offset' : '')
})
})
}
},
methods: {
taskEmoji(code) {
const map = {
waimai: '食',
group: '团',
invite: '邀',
sign: '签'
}
return map[code] || '券'
},
taskClass(code) {
const map = {
waimai: 'type-food',
group: 'type-group',
invite: 'type-invite',
sign: 'type-sign'
}
return map[code] || 'type-other'
},
btnText(t) {
if (t.actionType === 'auto') return '去完成'
if (t.code === 'sign') return t.canClaim ? '签到' : '已领取'
return t.canClaim ? '领取' : '已领取'
},
onClick(t) {
if (t.actionType === 'auto') {
this.$emit('go', t)
return
}
if (!t.canClaim) return
this.$emit('claim', t)
}
}
}
</script>
<style lang="scss" scoped>
.pt {
position: relative;
margin-top: 34rpx;
}
.pt-head {
display: flex;
align-items: flex-end;
justify-content: space-between;
margin-bottom: 22rpx;
}
.pt-kicker {
display: block;
color: #35D6A6;
font-size: 18rpx;
font-weight: 900;
letter-spacing: 3rpx;
margin-bottom: 4rpx;
}
.pt-title {
display: block;
color: #12342F;
font-size: 36rpx;
font-weight: 900;
}
.pt-sub {
color: #7E9691;
font-size: 22rpx;
font-weight: 600;
}
.pt-list {
position: relative;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.pt-list:before {
content: '';
position: absolute;
left: 42rpx;
right: 42rpx;
top: 102rpx;
height: 180rpx;
border-top: 3rpx dashed rgba(53,214,166,0.28);
border-radius: 50%;
transform: rotate(-7deg);
background: transparent;
}
.pt-item {
position: relative;
width: 318rpx;
min-height: 224rpx;
box-sizing: border-box;
padding: 26rpx 22rpx 24rpx;
margin-bottom: 24rpx;
border-radius: 36rpx;
background: linear-gradient(145deg, rgba(255,255,255,0.82), rgba(244,255,249,0.64));
border: 2rpx solid rgba(255,255,255,0.9);
box-shadow: 0 18rpx 42rpx rgba(53,214,166,0.1);
overflow: hidden;
}
.pt-item.offset {
margin-top: 54rpx;
transform: rotate(1.4deg);
}
.pt-item:not(.offset) {
transform: rotate(-1deg);
}
.pt-item:before {
content: '';
position: absolute;
right: -36rpx;
top: -40rpx;
width: 150rpx;
height: 150rpx;
border-radius: 50%;
background: rgba(53,214,166,0.12);
}
.pt-item.type-food:before { background: rgba(255,184,77,0.18); }
.pt-item.type-group:before { background: rgba(79,183,255,0.18); }
.pt-item.type-invite:before { background: rgba(143,124,255,0.16); }
.pt-item.type-sign:before { background: rgba(53,214,166,0.16); }
.pt-route-dot {
position: absolute;
left: 28rpx;
top: -8rpx;
width: 20rpx;
height: 20rpx;
border-radius: 50%;
background: #35D6A6;
border: 5rpx solid rgba(255,255,255,0.9);
box-shadow: 0 6rpx 16rpx rgba(53,214,166,0.22);
}
.pt-item-icon {
position: relative;
width: 72rpx;
height: 72rpx;
border-radius: 24rpx;
background: linear-gradient(145deg, #E5FFF1, #EAF8FF);
display: flex;
align-items: center;
justify-content: center;
color: #12342F;
font-size: 30rpx;
font-weight: 900;
box-shadow: inset 0 0 0 1rpx rgba(255,255,255,0.86);
}
.pt-item-mid {
position: relative;
margin-top: 18rpx;
}
.pt-item-name {
color: #12342F;
font-size: 28rpx;
font-weight: 900;
}
.pt-item-desc {
color: #7E9691;
font-size: 22rpx;
margin-top: 8rpx;
line-height: 32rpx;
min-height: 64rpx;
}
.pt-item-btn {
position: relative;
margin-top: 18rpx;
height: 58rpx;
padding: 0 18rpx;
border-radius: 999rpx;
background: linear-gradient(135deg, #35D6A6, #4FB7FF);
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 23rpx;
font-weight: 800;
box-shadow: 0 12rpx 26rpx rgba(53,214,166,0.22);
}
.pt-item-btn.auto {
background: rgba(18,52,47,0.08);
color: #22B889;
box-shadow: none;
}
.pt-item-btn.done {
background: rgba(18,52,47,0.06);
color: #9AA9A5;
box-shadow: none;
}
</style>