From e34586e3f020dc16d09f98ef0ebafec64d2faa78 Mon Sep 17 00:00:00 2001 From: H1d3rOne Date: Sun, 8 Mar 2026 05:17:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E6=AF=8F=E6=97=A5?= =?UTF-8?q?=E7=AD=BE=E5=88=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 显示一周签到进度,已签到显示绿色圆圈 - 今日显示橙色边框高亮 - 连续签到奖励递增:第1天5金币到第7天15金币 - 断签后重新从第1天开始计算 - 保存签到历史记录 --- xuan-deduct-uniapp/src/pages/mine/coins.vue | 272 +++++++++++++++++--- 1 file changed, 238 insertions(+), 34 deletions(-) diff --git a/xuan-deduct-uniapp/src/pages/mine/coins.vue b/xuan-deduct-uniapp/src/pages/mine/coins.vue index d79bd9f..24f730f 100644 --- a/xuan-deduct-uniapp/src/pages/mine/coins.vue +++ b/xuan-deduct-uniapp/src/pages/mine/coins.vue @@ -8,24 +8,37 @@ {{ coins }} - - 每日任务 + + + 每日签到 + 已连签 {{ streakDays }} 天 + - - - - 📅 + + + + {{ index + 1 }} - - 每日签到 - +5金币 - - - - {{ signedToday ? '已签到' : '签到' }} + {{ day.label }} + +{{ getDayReward(index) }} + + 连续签到奖励递增,第7天可获得{{ getDayReward(6) }}金币 + + + + + {{ signedToday ? '今日已签到' : '立即签到' }} + + 签到可获得 +{{ todayReward }} 金币 + + + + + 其他任务 + @@ -62,7 +75,11 @@ 金币说明 - 1. 每日签到可获得5金币\n2. 邀请好友注册可获得10金币\n3. 每次测算消耗1金币\n4. 会员用户无需消耗金币 + 1. 连续签到奖励递增:第1天5金币,第2天6金币...第7天15金币 +2. 断签后重新从第1天开始计算 +3. 邀请好友注册可获得10金币 +4. 每次测算消耗1金币 +5. 会员用户无需消耗金币 @@ -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; }