提交修改
CI / Server (Go) (push) Has been cancelled
CI / Web (Next.js) (push) Has been cancelled
CI / Mobile (React Native) (push) Has been cancelled
CI / Admin (React) (push) Has been cancelled
CI / Docker Build (push) Has been cancelled

This commit is contained in:
zeronline
2026-06-29 16:49:54 +08:00
parent 545329ac40
commit b01a5f91c3
43 changed files with 740 additions and 338 deletions
+2 -2
View File
@@ -2,10 +2,10 @@ const api = require('../../services/api')
const app = getApp()
Page({
data: { user: null, items: [], streaks: {}, loading: true },
data: { user: null, items: [], streaks: {}, loading: true, themeMode: 'light' },
onShow() {
if (!app.globalData.token) { wx.reLaunch({ url: '/pages/login/index' }); return }
this.setData({ user: app.globalData.user })
this.setData({ user: app.globalData.user, themeMode: app.globalData.themeMode })
this.loadItems()
},
onPullDownRefresh() { this.loadItems().then(() => wx.stopPullDownRefresh()) },
+24 -23
View File
@@ -1,31 +1,32 @@
<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 data-theme="{{themeMode}}">
<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>
</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 class="section-header">
<text class="section-title">今日打卡</text>
<button class="create-btn" bindtap="goCreate">+ 创建</button>
</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 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>
<view wx:if="{{loading}}" class="loading">加载中...</view>
+14 -15
View File
@@ -1,20 +1,19 @@
.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-card { background: var(--color-card); 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: var(--color-primary-gradient); 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; }
.header-name { font-size: 16px; font-weight: 600; display: block; color: var(--color-text); }
.header-sub { font-size: 13px; color: var(--color-text-secondary); }
.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; }
.section-title { font-size: 20px; font-weight: 700; color: var(--color-text); }
.create-btn { background: var(--color-primary); color: white; border: none; font-size: 14px; padding: 6px 14px; border-radius: 8px; }
.checkin-card { background: var(--color-card); 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: var(--color-active-bg); 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; }
.card-name { font-size: 16px; font-weight: 600; display: block; color: var(--color-text); }
.card-meta { font-size: 13px; color: var(--color-text-secondary); }
.card-streak { font-size: 14px; color: var(--color-primary); 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; }
.empty-text { font-size: 15px; color: var(--color-text-secondary); display: block; margin-top: 8px; }
.empty-sub { font-size: 13px; color: var(--color-text-secondary); }
.loading { text-align: center; padding: 40px; color: var(--color-text-secondary); font-size: 15px; }