| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <template>
- <view class="health-checkin-card">
- <view class="hcc-header">
- <text class="hcc-title">🏃 健康打卡</text>
- <text class="hcc-more" v-if="streak > 0">连续 {{ streak }} 天</text>
- </view>
- <view class="hcc-body">
- <template v-if="todayCheckedIn">
- <view class="hcc-done">
- <text class="hcc-done-icon">✓</text>
- <text class="hcc-done-text">今日已打卡</text>
- </view>
- <text class="hcc-energy">+{{ earnedEnergy }} 身能量</text>
- </template>
- <template v-else>
- <view class="hcc-undo" @click="doCheckin">
- <text class="hcc-btn">立即打卡</text>
- <text class="hcc-btn-tip">完成健康打卡获得身能量</text>
- </view>
- </template>
- </view>
- </view>
- </template>
- <script>
- export default {
- props: {
- childId: { type: Number, default: null }
- },
- data: function() {
- return {
- checkins: [],
- loading: false
- }
- },
- computed: {
- todayCheckedIn: function() {
- if (!this.checkins || this.checkins.length === 0) return false
- var today = this.getDateString(new Date())
- return this.checkins.some(function(c) {
- if (!c.checkinDate) return false
- var d = c.checkinDate
- if (typeof d === 'string') {
- return d.slice(0, 10) === today
- }
- return this.getDateString(new Date(d)).slice(0, 10) === today
- }.bind(this))
- },
- streak: function() {
- if (!this.checkins || this.checkins.length === 0) return 0
- var sorted = this.checkins.slice().sort(function(a, b) {
- if (!a.checkinDate || !b.checkinDate) return 0
- var da = new Date(a.checkinDate)
- var db = new Date(b.checkinDate)
- return db - da
- })
- var streak = 0
- var today = new Date()
- today.setHours(0, 0, 0, 0)
- var checkDate = new Date(today)
- for (var i = 0; i < sorted.length; i++) {
- var cDate = new Date(sorted[i].checkinDate)
- cDate.setHours(0, 0, 0, 0)
- var diff = Math.round((checkDate - cDate) / (1000 * 60 * 60 * 24))
- if (diff === 0 || diff === 1) {
- if (diff === 1) streak++
- if (diff === 0 && streak === 0) streak = 1
- checkDate = cDate
- checkDate.setDate(checkDate.getDate() - 1)
- } else {
- break
- }
- }
- return streak
- },
- earnedEnergy: function() {
- if (!this.checkins || this.checkins.length === 0) return 5
- var last = this.checkins[0]
- return last && last.earnedEnergy ? last.earnedEnergy : 5
- }
- },
- created: function() {
- this.loadCheckins()
- },
- methods: {
- getDateString: function(date) {
- var y = date.getFullYear()
- var m = ('' + (date.getMonth() + 1)).padStart(2, '0')
- var d = ('' + date.getDate()).padStart(2, '0')
- return y + '-' + m + '-' + d
- },
- loadCheckins: function() {
- var self = this
- if (!this.childId) return
- import('@/utils/api.js').then(function(api) {
- var now = new Date()
- var yearMonth = now.getFullYear() + '-' + ('' + (now.getMonth() + 1)).padStart(2, '0')
- api.healthCheckinList({
- childId: self.childId,
- yearMonth: yearMonth
- }).then(function(res) {
- if (res.data) {
- self.checkins = res.data
- }
- }).catch(function() {
- self.checkins = []
- })
- })
- },
- doCheckin: function() {
- var self = this
- if (!this.childId) {
- uni.showToast({ title: '请先选择孩子', icon: 'none' })
- return
- }
- if (this.loading) return
- this.loading = true
- import('@/utils/api.js').then(function(api) {
- api.healthCheckinCreate({
- childId: self.childId,
- checkinDate: self.getDateString(new Date()),
- behaviors: [],
- mood: 'happy'
- }).then(function(res) {
- self.loading = false
- uni.showToast({ title: '打卡成功!+' + (res.data && res.data.earnedEnergy || 5) + '身能量', icon: 'none' })
- self.checkins.unshift(res.data)
- }).catch(function() {
- self.loading = false
- })
- })
- }
- }
- }
- </script>
- <style scoped>
- .health-checkin-card {
- background: #fff;
- border-radius: 20rpx;
- padding: 24rpx;
- margin: 20rpx 20rpx 0 20rpx;
- box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
- }
- .hcc-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16rpx;
- }
- .hcc-title { font-size: 28rpx; font-weight: 700; color: #333; }
- .hcc-more { font-size: 22rpx; color: #F97316; }
- .hcc-body { display: flex; align-items: center; justify-content: center; }
- .hcc-done {
- display: flex;
- align-items: center;
- gap: 12rpx;
- padding: 20rpx 0;
- }
- .hcc-done-icon {
- width: 56rpx;
- height: 56rpx;
- border-radius: 28rpx;
- background: linear-gradient(135deg, #10B981, #34D399);
- color: #fff;
- font-size: 28rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .hcc-done-text { font-size: 30rpx; color: #10B981; font-weight: 600; }
- .hcc-energy { font-size: 22rpx; color: #999; margin-left: 16rpx; }
- .hcc-undo {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 12rpx 0;
- width: 100%;
- }
- .hcc-btn {
- background: linear-gradient(135deg, #FF8C42, #FFB074);
- color: #fff;
- font-size: 28rpx;
- font-weight: 600;
- padding: 16rpx 60rpx;
- border-radius: 40rpx;
- }
- .hcc-btn:active { opacity: 0.8; }
- .hcc-btn-tip { font-size: 22rpx; color: #999; margin-top: 8rpx; }
- </style>
|