首次提交

This commit is contained in:
zeronline
2026-06-25 08:39:47 +08:00
parent 20a93c703a
commit c5cccd346b
169 changed files with 24720 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
const api = require('../../services/api')
const app = getApp()
Page({
data: { user: null, items: [], streaks: {}, loading: true },
onShow() {
if (!app.globalData.token) { wx.reLaunch({ url: '/pages/login/index' }); return }
this.setData({ user: app.globalData.user })
this.loadItems()
},
onPullDownRefresh() { this.loadItems().then(() => wx.stopPullDownRefresh()) },
async loadItems() {
try {
const items = await api.get('/api/checkin/items')
const streaks = {}
for (const item of items.filter(i => i.status === 'active')) {
try { const s = await api.get('/api/checkin/streak/' + item.id); streaks[item.id] = s.streak } catch(e) {}
}
this.setData({ items: items.filter(i => i.status !== 'deleted'), streaks, loading: false })
} catch(e) { this.setData({ loading: false }) }
},
goCreate() { wx.navigateTo({ url: '/pages/checkin/create/index' }) },
goDetail(e) { wx.navigateTo({ url: '/pages/checkin/detail/index?id=' + e.currentTarget.dataset.id }) },
goProfile() { wx.switchTab({ url: '/pages/profile/index/index' }) },
})
+1
View File
@@ -0,0 +1 @@
{ "navigationBarTitleText": "寸进", "usingComponents": {} }
+31
View File
@@ -0,0 +1,31 @@
<view wx:if="{{!loading}}">
<view class="header-card">
<view class="avatar">{{user.nickname ? user.nickname[0] : (user.phone ? user.phone.slice(-4) : '?')}}</view>
<view class="header-info">
<text class="header-name">{{user.nickname || '用户'}}</text>
<text class="header-sub">积分 {{user.points}} · {{items.filter(i=>i.status==='active').length}} 个活跃项</text>
</view>
<button class="profile-btn" bindtap="goProfile">我的</button>
</view>
<view class="section-header">
<text class="section-title">今日打卡</text>
<button class="create-btn" bindtap="goCreate">+ 创建</button>
</view>
<view wx:for="{{items}}" wx:key="id" class="checkin-card" data-id="{{item.id}}" bindtap="goDetail" wx:for-item="item">
<view class="card-icon">{{item.icon || '📋'}}</view>
<view class="card-body">
<text class="card-name">{{item.name}}</text>
<text class="card-meta">{{item.category}} · {{item.cycleType}}</text>
</view>
<text class="card-streak" wx:if="{{streaks[item.id]}}">🔥 {{streaks[item.id]}}天</text>
</view>
<view class="empty" wx:if="{{items.length===0}}">
<text class="empty-icon">📋</text>
<text class="empty-text">还没有打卡项</text>
<text class="empty-sub">点击上方"创建"开始</text>
</view>
</view>
<view wx:if="{{loading}}" class="loading">加载中...</view>
+20
View File
@@ -0,0 +1,20 @@
.header-card { background: white; border-radius: 12px; margin: 12px 16px; padding: 14px 16px; display: flex; align-items: center; gap: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
.avatar { width: 44px; height: 44px; border-radius: 22px; background: linear-gradient(135deg, #FF6B35, #FF4D6D); display: flex; align-items: center; justify-content: center; font-size: 18px; color: white; font-weight: 600; flex-shrink: 0; }
.header-info { flex: 1; }
.header-name { font-size: 16px; font-weight: 600; display: block; }
.header-sub { font-size: 13px; color: #86868B; }
.profile-btn { background: none; border: 1px solid #FF6B35; color: #FF6B35; font-size: 14px; padding: 4px 12px; border-radius: 8px; }
.section-header { display: flex; justify-content: space-between; align-items: center; padding: 20px 16px 8px; }
.section-title { font-size: 20px; font-weight: 700; }
.create-btn { background: #FF6B35; color: white; border: none; font-size: 14px; padding: 6px 14px; border-radius: 8px; }
.checkin-card { background: white; border-radius: 12px; margin: 8px 16px; padding: 14px 16px; display: flex; align-items: center; gap: 14px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
.card-icon { width: 44px; height: 44px; border-radius: 12px; background: #FFF0EB; display: flex; align-items: center; justify-content: center; font-size: 22px; }
.card-body { flex: 1; }
.card-name { font-size: 16px; font-weight: 600; display: block; }
.card-meta { font-size: 13px; color: #86868B; }
.card-streak { font-size: 14px; color: #FF6B35; font-weight: 600; }
.empty { text-align: center; padding: 60px 16px; }
.empty-icon { font-size: 40px; }
.empty-text { font-size: 15px; color: #86868B; display: block; margin-top: 8px; }
.empty-sub { font-size: 13px; color: #86868B; }
.loading { text-align: center; padding: 40px; color: #86868B; font-size: 15px; }