feat: 优化每日签到功能

- 显示一周签到进度,已签到显示绿色圆圈
- 今日显示橙色边框高亮
- 连续签到奖励递增:第1天5金币到第7天15金币
- 断签后重新从第1天开始计算
- 保存签到历史记录
This commit is contained in:
H1d3rOne committed 2026-03-08 05:17:17 +08:00
1 parent 058bf0c2bd
commit e34586e3f0
1 file changed
+238 -34
+238 -34
View File
@@ -8,24 +8,37 @@
<text class="coins-value">{{ coins }}</text>
</view>
<view class="task-card">
<text class="task-title">每日任务</text>
<view class="sign-card">
<view class="sign-header">
<text class="sign-title">每日签到</text>
<text class="sign-streak">已连签 {{ streakDays }} 天</text>
</view>
<view class="task-item">
<view class="task-left">
<view class="task-icon">
<text class="task-icon-text">📅</text>
<view class="week-progress">
<view class="day-item" v-for="(day, index) in weekDays" :key="index">
<view class="day-circle" :class="{ signed: day.signed, today: day.isToday }">
<text class="day-num">{{ index + 1 }}</text>
</view>
<view class="task-info">
<text class="task-name">每日签到</text>
<text class="task-reward">+5金币</text>
</view>
</view>
<view class="task-btn" :class="{ done: signedToday }" @click="signIn">
<text class="task-btn-text">{{ signedToday ? '已签到' : '签到' }}</text>
<text class="day-label">{{ day.label }}</text>
<text class="day-reward">+{{ getDayReward(index) }}</text>
</view>
</view>
<view class="sign-info">
<text class="sign-tip">连续签到奖励递增,第7天可获得{{ getDayReward(6) }}金币</text>
</view>
<view class="sign-btn-wrapper">
<view class="sign-btn" :class="{ done: signedToday }" @click="signIn">
<text class="sign-btn-text">{{ signedToday ? '今日已签到' : '立即签到' }}</text>
</view>
<text class="sign-reward-tip" v-if="!signedToday">签到可获得 +{{ todayReward }} 金币</text>
</view>
</view>
<view class="task-card">
<text class="task-title">其他任务</text>
<view class="task-item">
<view class="task-left">
<view class="task-icon">
@@ -62,7 +75,11 @@
<view class="tips-card">
<text class="tips-title">金币说明</text>
<text class="tips-content">1. 每日签到可获得5金币\n2. 邀请好友注册可获得10金币\n3. 每次测算消耗1金币\n4. 会员用户无需消耗金币</text>
<text class="tips-content">1. 连续签到奖励递增:第1天5金币,第2天6金币...第7天15金币
2. 断签后重新从第1天开始计算
3. 邀请好友注册可获得10金币
4. 每次测算消耗1金币
5. 会员用户无需消耗金币</text>
</view>
</view>
</template>
@@ -73,14 +90,20 @@ export default {
return {
coins: 10,
signedToday: false,
records: [
{ name: '新用户奖励', amount: 10, time: '2024-01-01 12:00' }
]
streakDays: 0,
weekDays: [],
records: []
}
},
computed: {
todayReward() {
return this.getDayReward(this.streakDays % 7)
}
},
onShow() {
this.loadCoins()
this.checkSignIn()
this.initWeekProgress()
this.loadRecords()
},
onShareAppMessage() {
return {
@@ -90,16 +113,53 @@ export default {
}
},
methods: {
getDayReward(dayIndex) {
const rewards = [5, 6, 7, 8, 10, 12, 15]
return rewards[dayIndex % 7]
},
loadCoins() {
const coins = uni.getStorageSync('userCoins')
if (coins) {
this.coins = parseInt(coins)
}
},
checkSignIn() {
const lastSignIn = uni.getStorageSync('lastSignInDate')
const today = new Date().toDateString()
this.signedToday = lastSignIn === today
loadRecords() {
const records = uni.getStorageSync('coinRecords')
if (records) {
this.records = JSON.parse(records)
}
},
saveRecords() {
uni.setStorageSync('coinRecords', JSON.stringify(this.records))
},
initWeekProgress() {
const today = new Date()
const dayOfWeek = today.getDay()
const weekLabels = ['日', '一', '二', '三', '四', '五', '六']
const lastSignInStr = uni.getStorageSync('lastSignInDate')
const streakStr = uni.getStorageSync('streakDays')
this.streakDays = streakStr ? parseInt(streakStr) : 0
const todayStr = this.formatDate(today)
this.signedToday = lastSignInStr === todayStr
const signInHistory = uni.getStorageSync('signInHistory') || '{}'
const history = JSON.parse(signInHistory)
this.weekDays = []
for (let i = 0; i < 7; i++) {
const date = new Date(today)
date.setDate(today.getDate() - dayOfWeek + i)
const dateStr = this.formatDate(date)
this.weekDays.push({
label: weekLabels[i],
signed: history[dateStr] === true,
isToday: i === dayOfWeek,
date: dateStr
})
}
},
signIn() {
if (this.signedToday) {
@@ -107,20 +167,43 @@ export default {
return
}
this.coins += 5
uni.setStorageSync('userCoins', this.coins)
const today = new Date()
const todayStr = this.formatDate(today)
const lastSignInStr = uni.getStorageSync('lastSignInDate')
const today = new Date().toDateString()
uni.setStorageSync('lastSignInDate', today)
const yesterday = new Date(today)
yesterday.setDate(today.getDate() - 1)
const yesterdayStr = this.formatDate(yesterday)
if (lastSignInStr === yesterdayStr) {
this.streakDays++
} else {
this.streakDays = 1
}
const reward = this.getDayReward((this.streakDays - 1) % 7)
this.coins += reward
uni.setStorageSync('userCoins', this.coins)
uni.setStorageSync('lastSignInDate', todayStr)
uni.setStorageSync('streakDays', this.streakDays)
const signInHistory = uni.getStorageSync('signInHistory') || '{}'
const history = JSON.parse(signInHistory)
history[todayStr] = true
uni.setStorageSync('signInHistory', JSON.stringify(history))
this.records.unshift({
name: '每日签到',
amount: 5,
name: `每日签到(连续${this.streakDays}天)`,
amount: reward,
time: this.formatTime(new Date())
})
this.saveRecords()
this.signedToday = true
uni.showToast({ title: '签到成功 +5金币', icon: 'success' })
this.initWeekProgress()
uni.showToast({ title: `签到成功 +${reward}金币`, icon: 'success' })
},
inviteFriend() {
uni.showShareMenu({
@@ -128,6 +211,12 @@ export default {
menus: ['shareAppMessage']
})
},
formatDate(date) {
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, '0')
const d = String(date.getDate()).padStart(2, '0')
return `${y}-${m}-${d}`
},
formatTime(date) {
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, '0')
@@ -188,6 +277,125 @@ page {
color: #78350F;
}
.sign-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 24rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(16, 185, 129, 0.1);
border: 2rpx solid rgba(16, 185, 129, 0.1);
}
.sign-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
.sign-title {
font-size: 30rpx;
font-weight: 600;
color: #065F46;
}
.sign-streak {
font-size: 24rpx;
color: #F59E0B;
font-weight: 500;
}
.week-progress {
display: flex;
justify-content: space-between;
margin-bottom: 24rpx;
}
.day-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.day-circle {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
background: #E5E7EB;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 8rpx;
}
.day-circle.signed {
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
}
.day-circle.today {
border: 3rpx solid #F59E0B;
}
.day-num {
font-size: 24rpx;
color: #6B7280;
font-weight: 500;
}
.day-circle.signed .day-num {
color: #ffffff;
}
.day-label {
font-size: 20rpx;
color: #9CA3AF;
margin-bottom: 4rpx;
}
.day-reward {
font-size: 18rpx;
color: #F59E0B;
}
.sign-info {
text-align: center;
margin-bottom: 24rpx;
}
.sign-tip {
font-size: 24rpx;
color: #6B7280;
}
.sign-btn-wrapper {
display: flex;
flex-direction: column;
align-items: center;
}
.sign-btn {
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
padding: 20rpx 80rpx;
border-radius: 40rpx;
margin-bottom: 12rpx;
}
.sign-btn.done {
background: #D1D5DB;
}
.sign-btn-text {
font-size: 30rpx;
color: #ffffff;
font-weight: 600;
}
.sign-reward-tip {
font-size: 22rpx;
color: #F59E0B;
}
.task-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 24rpx;
@@ -259,10 +467,6 @@ page {
border-radius: 32rpx;
}
.task-btn.done {
background: #D1D5DB;
}
.task-btn-text {
font-size: 26rpx;
color: #ffffff;
@@ -356,7 +560,7 @@ page {
}
.tips-content {
font-size: 26rpx;
font-size: 24rpx;
color: #374151;
line-height: 1.8;
}