提交修改
This commit is contained in:
+45
-2
@@ -2,7 +2,8 @@ App({
|
||||
globalData: {
|
||||
token: '',
|
||||
user: null,
|
||||
apiUrl: 'http://localhost:8080'
|
||||
apiUrl: 'http://localhost:8080',
|
||||
themeMode: 'light',
|
||||
},
|
||||
onLaunch() {
|
||||
const token = wx.getStorageSync('token')
|
||||
@@ -13,5 +14,47 @@ App({
|
||||
if (user) this.globalData.user = user
|
||||
} catch(e) {}
|
||||
}
|
||||
}
|
||||
this.initTheme()
|
||||
},
|
||||
initTheme() {
|
||||
const stored = wx.getStorageSync('inchstep-theme')
|
||||
if (stored === 'light' || stored === 'dark') {
|
||||
this.globalData.themeMode = stored
|
||||
} else {
|
||||
try {
|
||||
const sysInfo = wx.getSystemInfoSync()
|
||||
this.globalData.themeMode = sysInfo.theme === 'dark' ? 'dark' : 'light'
|
||||
} catch(e) {}
|
||||
}
|
||||
this.applyTheme(this.globalData.themeMode)
|
||||
},
|
||||
applyTheme(mode) {
|
||||
this.globalData.themeMode = mode
|
||||
wx.setStorageSync('inchstep-theme', mode)
|
||||
try {
|
||||
wx.setNavigationBarColor({
|
||||
frontColor: mode === 'dark' ? '#ffffff' : '#000000',
|
||||
backgroundColor: mode === 'dark' ? '#1C1C1E' : '#F5F5F7',
|
||||
})
|
||||
wx.setTabBarStyle({
|
||||
backgroundColor: mode === 'dark' ? '#1C1C1E' : '#F5F5F7',
|
||||
borderStyle: mode === 'dark' ? 'black' : 'white',
|
||||
})
|
||||
} catch(e) {}
|
||||
this.notifyPages(mode)
|
||||
},
|
||||
toggleTheme() {
|
||||
const newMode = this.globalData.themeMode === 'light' ? 'dark' : 'light'
|
||||
this.applyTheme(newMode)
|
||||
},
|
||||
notifyPages(mode) {
|
||||
const pages = getCurrentPages()
|
||||
pages.forEach(page => {
|
||||
if (page.setData && typeof page.setThemeData === 'function') {
|
||||
page.setThemeData(mode)
|
||||
} else if (page.setData) {
|
||||
page.setData({ themeMode: mode })
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
+39
-5
@@ -1,6 +1,40 @@
|
||||
page { font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif; background: #F5F5F7; color: #1D1D1F; }
|
||||
.card { background: white; border-radius: 12px; margin: 8px 16px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.btn-primary { width: 100%; padding: 14px; background: linear-gradient(135deg, #FF6B35, #FF4D6D); color: white; border: none; border-radius: 10px; font-size: 17px; font-weight: 600; text-align: center; }
|
||||
.input-field { width: 100%; padding: 14px 16px; background: #f8f8fa; border: 1px solid #E5E5EA; border-radius: 10px; font-size: 17px; }
|
||||
page {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
|
||||
--color-primary: #FF6B35;
|
||||
--color-primary-light: #FF8C5A;
|
||||
--color-primary-gradient: linear-gradient(135deg, #FF6B35, #FF4D6D);
|
||||
--color-accent: #7209B7;
|
||||
--color-bg: #F5F5F7;
|
||||
--color-card: #FFFFFF;
|
||||
--color-text: #1D1D1F;
|
||||
--color-text-secondary: #86868B;
|
||||
--color-border: #E5E5EA;
|
||||
--color-nav-bg: rgba(245,245,247,0.95);
|
||||
--color-success: #34C759;
|
||||
--color-warning: #FF9500;
|
||||
--color-error: #FF3B30;
|
||||
--color-input-bg: #f8f8fa;
|
||||
--color-active-bg: #FFF0EB;
|
||||
--color-divider: #F0F0F0;
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
}
|
||||
page[data-theme="dark"] {
|
||||
--color-bg: #1C1C1E;
|
||||
--color-card: #2C2C2E;
|
||||
--color-text: #F5F5F7;
|
||||
--color-text-secondary: #98989D;
|
||||
--color-border: #38383A;
|
||||
--color-nav-bg: rgba(28,28,30,0.95);
|
||||
--color-accent: #BB86FC;
|
||||
--color-error: #FF453A;
|
||||
--color-input-bg: #3A3A3C;
|
||||
--color-active-bg: #3A3A3C;
|
||||
--color-divider: #38383A;
|
||||
}
|
||||
|
||||
.card { background: var(--color-card); border-radius: 12px; margin: 8px 16px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.btn-primary { width: 100%; padding: 14px; background: var(--color-primary-gradient); color: white; border: none; border-radius: 10px; font-size: 17px; font-weight: 600; text-align: center; }
|
||||
.input-field { width: 100%; padding: 14px 16px; background: var(--color-input-bg); border: 1px solid var(--color-border); border-radius: 10px; font-size: 17px; }
|
||||
.page-title { font-size: 28px; font-weight: 600; padding: 20px 16px 8px; }
|
||||
.page-subtitle { font-size: 15px; color: #86868B; padding: 0 16px 20px; }
|
||||
.page-subtitle { font-size: 15px; color: var(--color-text-secondary); padding: 0 16px 20px; }
|
||||
@@ -1,7 +1,7 @@
|
||||
.card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: white;
|
||||
background: var(--color-card);
|
||||
border-radius: 12px;
|
||||
margin: 0 12px 8px;
|
||||
padding: 14px;
|
||||
@@ -12,7 +12,7 @@
|
||||
.card-icon {
|
||||
width: 44px; height: 44px;
|
||||
border-radius: 12px;
|
||||
background: #FFF0EB;
|
||||
background: var(--color-active-bg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -20,7 +20,7 @@
|
||||
margin-right: 14px;
|
||||
}
|
||||
.card-body { flex: 1; display: flex; flex-direction: column; gap: 2px; }
|
||||
.card-name { font-size: 16px; font-weight: 600; }
|
||||
.card-meta { font-size: 13px; color: #86868B; }
|
||||
.done-badge { font-size: 12px; color: #34C759; font-weight: 600; margin-top: 2px; }
|
||||
.card-streak { font-size: 14px; color: #FF6B35; font-weight: 600; }
|
||||
.card-name { font-size: 16px; font-weight: 600; color: var(--color-text); }
|
||||
.card-meta { font-size: 13px; color: var(--color-text-secondary); }
|
||||
.done-badge { font-size: 12px; color: var(--color-success); font-weight: 600; margin-top: 2px; }
|
||||
.card-streak { font-size: 14px; color: var(--color-primary); font-weight: 600; }
|
||||
@@ -1,6 +1,9 @@
|
||||
const app = getApp()
|
||||
|
||||
Component({
|
||||
properties: {
|
||||
active: { type: String, value: 'home' },
|
||||
themeMode: { type: String, value: 'light' },
|
||||
tabs: {
|
||||
type: Array,
|
||||
value: [
|
||||
@@ -10,6 +13,11 @@ Component({
|
||||
],
|
||||
},
|
||||
},
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.setData({ themeMode: app.globalData.themeMode })
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onSwitch(e) {
|
||||
this.triggerEvent('switch', { key: e.currentTarget.dataset.key })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<view class="nav-bar">
|
||||
<view data-theme="{{themeMode}}" class="nav-bar">
|
||||
<view wx:for="{{tabs}}" wx:key="key" class="nav-item" data-key="{{item.key}}" bindtap="onSwitch">
|
||||
<text class="nav-icon">{{item.icon}}</text>
|
||||
<text class="nav-label {{active===item.key?'active':''}}">{{item.label}}</text>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
padding: 8px 0 24px;
|
||||
border-top: 0.5px solid #E5E5EA;
|
||||
background: rgba(245,245,247,0.95);
|
||||
border-top: 0.5px solid var(--color-border);
|
||||
background: var(--color-nav-bg);
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -20,5 +20,5 @@
|
||||
padding: 4px;
|
||||
}
|
||||
.nav-icon { font-size: 22px; }
|
||||
.nav-label { font-size: 10px; color: #86868B; }
|
||||
.nav-label.active { color: #FF6B35; font-weight: 600; }
|
||||
.nav-label { font-size: 10px; color: var(--color-text-secondary); }
|
||||
.nav-label.active { color: var(--color-primary); font-weight: 600; }
|
||||
@@ -1,6 +1,10 @@
|
||||
const api = require('../../../services/api')
|
||||
const app = getApp()
|
||||
Page({
|
||||
data: { name: '', category: 'study', cycleType: 'daily', dailyGoal: '', privacy: 2, submitting: false },
|
||||
data: { name: '', category: 'study', cycleType: 'daily', dailyGoal: '', privacy: 2, submitting: false, themeMode: 'light' },
|
||||
onShow() {
|
||||
this.setData({ themeMode: app.globalData.themeMode })
|
||||
},
|
||||
onNameInput(e) { this.setData({ name: e.detail.value }) },
|
||||
onGoalInput(e) { this.setData({ dailyGoal: e.detail.value }) },
|
||||
setCategory(e) { this.setData({ category: e.currentTarget.dataset.cat }) },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<view class="form">
|
||||
<view data-theme="{{themeMode}}"><view class="form">
|
||||
<text class="label">名称 *</text>
|
||||
<input class="input-field" value="{{name}}" bindinput="onNameInput" placeholder="如「每天背单词」" style="margin-bottom:20px" />
|
||||
|
||||
@@ -29,4 +29,4 @@
|
||||
</view>
|
||||
|
||||
<button class="btn-primary" style="margin-top:32px" loading="{{submitting}}" disabled="{{submitting}}" bindtap="onSubmit">创建打卡项</button>
|
||||
</view>
|
||||
</view></view>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
.form { padding: 16px; }
|
||||
.label { font-size: 13px; color: #86868B; margin-bottom: 6px; display: block; }
|
||||
.label { font-size: 13px; color: var(--color-text-secondary); margin-bottom: 6px; display: block; }
|
||||
.category-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
|
||||
.cat-item { padding: 12px 8px; border-radius: 10px; border: 2px solid #E5E5EA; background: #f8f8fa; text-align: center; font-size: 14px; }
|
||||
.cat-item.active { border-color: #FF6B35; background: #FFF0EB; font-weight: 600; }
|
||||
.cat-item { padding: 12px 8px; border-radius: 10px; border: 2px solid var(--color-border); background: var(--color-input-bg); text-align: center; font-size: 14px; color: var(--color-text); }
|
||||
.cat-item.active { border-color: var(--color-primary); background: var(--color-active-bg); font-weight: 600; }
|
||||
.cycle-row { display: flex; gap: 8px; }
|
||||
.cycle-item { padding: 8px 16px; border-radius: 8px; border: 1.5px solid #E5E5EA; background: #f8f8fa; font-size: 14px; }
|
||||
.cycle-item.active { border-color: #FF6B35; background: #FFF0EB; font-weight: 600; }
|
||||
.cycle-item { padding: 8px 16px; border-radius: 8px; border: 1.5px solid var(--color-border); background: var(--color-input-bg); font-size: 14px; color: var(--color-text); }
|
||||
.cycle-item.active { border-color: var(--color-primary); background: var(--color-active-bg); font-weight: 600; }
|
||||
.privacy-row { display: flex; gap: 8px; }
|
||||
.privacy-item { padding: 8px 16px; border-radius: 8px; border: 1.5px solid #E5E5EA; background: #f8f8fa; font-size: 14px; }
|
||||
.privacy-item.active { border-color: #FF6B35; background: #FFF0EB; font-weight: 600; }
|
||||
.privacy-item { padding: 8px 16px; border-radius: 8px; border: 1.5px solid var(--color-border); background: var(--color-input-bg); font-size: 14px; color: var(--color-text); }
|
||||
.privacy-item.active { border-color: var(--color-primary); background: var(--color-active-bg); font-weight: 600; }
|
||||
@@ -1,6 +1,10 @@
|
||||
const api = require('../../../services/api')
|
||||
const app = getApp()
|
||||
Page({
|
||||
data: { item: null, streak: 0, records: [], year: 0, month: 0, days: [], loading: true, showActions: false },
|
||||
data: { item: null, streak: 0, records: [], year: 0, month: 0, days: [], loading: true, showActions: false, themeMode: 'light' },
|
||||
onShow() {
|
||||
this.setData({ themeMode: app.globalData.themeMode })
|
||||
},
|
||||
onLoad(options) {
|
||||
const now = new Date()
|
||||
this.setData({ id: options.id, year: now.getFullYear(), month: now.getMonth() + 1 })
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<view wx:if="{{loading}}" class="loading">加载中...</view>
|
||||
<view wx:else>
|
||||
<view wx:else><view data-theme="{{themeMode}}">
|
||||
<!-- Actions button -->
|
||||
<view class="action-btn" bindtap="toggleActions">⋯</view>
|
||||
<view class="action-menu" wx:if="{{showActions}}">
|
||||
@@ -41,4 +41,4 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view></view>
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
.loading { text-align: center; padding: 40px; color: #86868B; }
|
||||
.card { background: white; border-radius: 12px; margin: 8px 16px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.loading { text-align: center; padding: 40px; color: var(--color-text-secondary); }
|
||||
.card { background: var(--color-card); border-radius: 12px; margin: 8px 16px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.action-btn { position: absolute; right: 16px; top: 12px; font-size: 20px; padding: 4px 8px; z-index: 10; }
|
||||
.action-menu { position: absolute; right: 16px; top: 44px; background: white; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); z-index: 10; min-width: 120px; }
|
||||
.action-item { padding: 12px 16px; font-size: 14px; border-bottom: 0.5px solid #E5E5EA; }
|
||||
.action-menu { position: absolute; right: 16px; top: 44px; background: var(--color-card); border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); z-index: 10; min-width: 120px; }
|
||||
.action-item { padding: 12px 16px; font-size: 14px; border-bottom: 0.5px solid var(--color-border); }
|
||||
.action-item:last-child { border-bottom: none; }
|
||||
.item-header { display: flex; align-items: center; gap: 12px; }
|
||||
.item-icon { width: 52px; height: 52px; border-radius: 14px; background: #FFF0EB; display: flex; align-items: center; justify-content: center; font-size: 26px; }
|
||||
.item-name { font-size: 18px; font-weight: 700; display: block; }
|
||||
.item-meta { font-size: 13px; color: #86868B; display: block; margin-top: 2px; }
|
||||
.item-goal { font-size: 13px; color: #86868B; display: block; margin-top: 2px; }
|
||||
.stats-row { display: flex; justify-content: space-around; background: white; border-radius: 12px; margin: 8px 16px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.item-icon { width: 52px; height: 52px; border-radius: 14px; background: var(--color-active-bg); display: flex; align-items: center; justify-content: center; font-size: 26px; }
|
||||
.item-name { font-size: 18px; font-weight: 700; display: block; color: var(--color-text); }
|
||||
.item-meta { font-size: 13px; color: var(--color-text-secondary); display: block; margin-top: 2px; }
|
||||
.item-goal { font-size: 13px; color: var(--color-text-secondary); display: block; margin-top: 2px; }
|
||||
.stats-row { display: flex; justify-content: space-around; background: var(--color-card); border-radius: 12px; margin: 8px 16px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.stat { text-align: center; }
|
||||
.stat-num { font-size: 28px; font-weight: 700; color: #FF6B35; display: block; }
|
||||
.stat-lbl { font-size: 13px; color: #86868B; }
|
||||
.stat-num { font-size: 28px; font-weight: 700; color: var(--color-primary); display: block; }
|
||||
.stat-lbl { font-size: 13px; color: var(--color-text-secondary); }
|
||||
.calendar { padding: 16px; }
|
||||
.cal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; font-size: 16px; font-weight: 600; }
|
||||
.cal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; font-size: 16px; font-weight: 600; color: var(--color-text); }
|
||||
.cal-nav { font-size: 18px; padding: 4px 8px; }
|
||||
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; text-align: center; }
|
||||
.cal-weekday { font-size: 12px; color: #86868B; padding: 6px 0; }
|
||||
.cal-day { padding: 8px 0; font-size: 14px; border-radius: 8px; position: relative; }
|
||||
.cal-weekday { font-size: 12px; color: var(--color-text-secondary); padding: 6px 0; }
|
||||
.cal-day { padding: 8px 0; font-size: 14px; border-radius: 8px; position: relative; color: var(--color-text); }
|
||||
.cal-day.checked { font-weight: 600; }
|
||||
.cal-day.today { background: #FFF0EB; }
|
||||
.cal-dot { width: 6px; height: 6px; border-radius: 3px; background: #34C759; margin: 2px auto 0; }
|
||||
.cal-day.today { background: var(--color-active-bg); }
|
||||
.cal-dot { width: 6px; height: 6px; border-radius: 3px; background: var(--color-success); margin: 2px auto 0; }
|
||||
@@ -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()) },
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -2,7 +2,10 @@ const api = require('../../services/api')
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: { phone: '', loading: false, error: '' },
|
||||
data: { phone: '', loading: false, error: '', themeMode: 'light' },
|
||||
onShow() {
|
||||
this.setData({ themeMode: app.globalData.themeMode })
|
||||
},
|
||||
onLoad() {
|
||||
if (app.globalData.token) wx.reLaunch({ url: '/pages/index/index' })
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
page { background: white; }
|
||||
.container { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; padding: 32px; box-sizing: border-box; }
|
||||
.logo-area { text-align: center; margin-bottom: 48px; }
|
||||
.logo { width: 80px; height: 80px; line-height: 80px; border-radius: 20px; background: linear-gradient(135deg, #FF6B35, #FF4D6D); text-align: center; font-size: 36px; margin: 0 auto 16px; }
|
||||
.slogan { font-size: 28px; font-weight: 700; }
|
||||
.sub-slogan { font-size: 15px; color: #86868B; margin-top: 4px; }
|
||||
.error { font-size: 13px; color: #FF3B30; margin-bottom: 12px; text-align: center; }
|
||||
.logo { width: 80px; height: 80px; line-height: 80px; border-radius: 20px; background: var(--color-primary-gradient); text-align: center; font-size: 36px; margin: 0 auto 16px; }
|
||||
.slogan { font-size: 28px; font-weight: 700; color: var(--color-text); }
|
||||
.sub-slogan { font-size: 15px; color: var(--color-text-secondary); margin-top: 4px; }
|
||||
.error { font-size: 13px; color: var(--color-error); margin-bottom: 12px; text-align: center; }
|
||||
.btn-primary { margin-top: 12px; }
|
||||
.tip { font-size: 13px; color: #86868B; margin-top: 16px; text-align: center; }
|
||||
.tip { font-size: 13px; color: var(--color-text-secondary); margin-top: 16px; text-align: center; }
|
||||
@@ -2,9 +2,10 @@ const api = require('../../../services/api')
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: { user: null },
|
||||
data: { user: null, themeMode: 'light' },
|
||||
onShow() {
|
||||
if (!app.globalData.token) { wx.reLaunch({ url: '/pages/login/index' }); return }
|
||||
this.setData({ themeMode: app.globalData.themeMode })
|
||||
this.loadProfile()
|
||||
},
|
||||
async loadProfile() {
|
||||
@@ -16,6 +17,10 @@ Page({
|
||||
},
|
||||
goEdit() { wx.navigateTo({ url: '/pages/profile/edit/index' }) },
|
||||
goAchievements() { wx.navigateTo({ url: '/pages/achievements/index' }) },
|
||||
onThemeToggle(e) {
|
||||
app.toggleTheme()
|
||||
this.setData({ themeMode: app.globalData.themeMode })
|
||||
},
|
||||
onLogout() {
|
||||
wx.showModal({ title: '确认退出', content: '确定要退出登录吗?', success: (res) => {
|
||||
if (res.confirm) {
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
<view class="profile-card" wx:if="{{user}}">
|
||||
<view class="profile-avatar">{{(user.nickname?.[0]) || (user.phone?.slice(-4)) || '?'}}</view>
|
||||
<text class="profile-name">{{user.nickname || '未设置昵称'}}</text>
|
||||
<text class="profile-bio">{{user.bio || '还没有个性签名'}}</text>
|
||||
</view>
|
||||
<view data-theme="{{themeMode}}">
|
||||
<view class="profile-card" wx:if="{{user}}">
|
||||
<view class="profile-avatar">{{(user.nickname?.[0]) || (user.phone?.slice(-4)) || '?'}}</view>
|
||||
<text class="profile-name">{{user.nickname || '未设置昵称'}}</text>
|
||||
<text class="profile-bio">{{user.bio || '还没有个性签名'}}</text>
|
||||
</view>
|
||||
|
||||
<view class="stats-card">
|
||||
<view class="stat-item"><text class="stat-value">{{user?.points || 0}}</text><text class="stat-label">积分</text></view>
|
||||
<view class="stat-item"><text class="stat-value">--</text><text class="stat-label">连续</text></view>
|
||||
<view class="stat-item"><text class="stat-value">--</text><text class="stat-label">徽章</text></view>
|
||||
</view>
|
||||
<view class="stats-card">
|
||||
<view class="stat-item"><text class="stat-value">{{user?.points || 0}}</text><text class="stat-label">积分</text></view>
|
||||
<view class="stat-item"><text class="stat-value">--</text><text class="stat-label">连续</text></view>
|
||||
<view class="stat-item"><text class="stat-value">--</text><text class="stat-label">徽章</text></view>
|
||||
</view>
|
||||
|
||||
<view class="menu-card">
|
||||
<view class="menu-item" bindtap="goAchievements"><text>成就徽章</text><text class="menu-arrow">→</text></view>
|
||||
<view class="menu-item" bindtap="onLogout" style="color:#FF3B30"><text>退出登录</text><text class="menu-arrow">→</text></view>
|
||||
<view class="menu-card">
|
||||
<view class="menu-item" bindtap="goAchievements"><text>成就徽章</text><text class="menu-arrow">→</text></view>
|
||||
<view class="menu-item"><text>深色模式</text><switch checked="{{themeMode === 'dark'}}" bindchange="onThemeToggle" color="#FF6B35" /></view>
|
||||
<view class="menu-item" bindtap="onLogout"><text style="color:var(--color-error)">退出登录</text><text class="menu-arrow">→</text></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
.profile-card { background: white; border-radius: 12px; margin: 12px 16px; padding: 32px 16px; text-align: center; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.profile-avatar { width: 72px; height: 72px; border-radius: 36px; background: linear-gradient(135deg,#FF6B35,#FF4D6D); display: flex; align-items: center; justify-content: center; font-size: 28px; color: white; font-weight: 600; margin: 0 auto 12px; }
|
||||
.profile-name { font-size: 22px; font-weight: 700; display: block; }
|
||||
.profile-bio { font-size: 14px; color: #86868B; margin-top: 4px; display: block; }
|
||||
.stats-card { background: white; border-radius: 12px; margin: 8px 16px; padding: 16px; display: flex; justify-content: space-around; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.profile-card { background: var(--color-card); border-radius: 12px; margin: 12px 16px; padding: 32px 16px; text-align: center; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.profile-avatar { width: 72px; height: 72px; border-radius: 36px; background: var(--color-primary-gradient); display: flex; align-items: center; justify-content: center; font-size: 28px; color: white; font-weight: 600; margin: 0 auto 12px; }
|
||||
.profile-name { font-size: 22px; font-weight: 700; display: block; color: var(--color-text); }
|
||||
.profile-bio { font-size: 14px; color: var(--color-text-secondary); margin-top: 4px; display: block; }
|
||||
.stats-card { background: var(--color-card); border-radius: 12px; margin: 8px 16px; padding: 16px; display: flex; justify-content: space-around; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.stat-item { text-align: center; }
|
||||
.stat-value { font-size: 24px; font-weight: 700; color: #FF6B35; display: block; }
|
||||
.stat-label { font-size: 13px; color: #86868B; }
|
||||
.menu-card { background: white; border-radius: 12px; margin: 8px 16px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.menu-item { display: flex; justify-content: space-between; align-items: center; padding: 14px 16px; border-bottom: 0.5px solid #E5E5EA; font-size: 15px; }
|
||||
.stat-value { font-size: 24px; font-weight: 700; color: var(--color-primary); display: block; }
|
||||
.stat-label { font-size: 13px; color: var(--color-text-secondary); }
|
||||
.menu-card { background: var(--color-card); border-radius: 12px; margin: 8px 16px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.menu-item { display: flex; justify-content: space-between; align-items: center; padding: 14px 16px; border-bottom: 0.5px solid var(--color-border); font-size: 15px; color: var(--color-text); }
|
||||
.menu-item:last-child { border-bottom: none; }
|
||||
.menu-arrow { font-size: 15px; color: #86868B; }
|
||||
.menu-arrow { font-size: 15px; color: var(--color-text-secondary); }
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
const api = require('../../../services/api')
|
||||
const app = getApp()
|
||||
Page({
|
||||
data: { posts: [], page: 1, loading: true, showCreate: false, content: '' },
|
||||
onShow() { this.loadFeed() },
|
||||
data: { posts: [], page: 1, loading: true, showCreate: false, content: '', themeMode: 'light' },
|
||||
onShow() {
|
||||
this.setData({ themeMode: app.globalData.themeMode })
|
||||
this.loadFeed()
|
||||
},
|
||||
onPullDownRefresh() { this.setData({ page: 1 }); this.loadFeed().then(() => wx.stopPullDownRefresh()) },
|
||||
async loadFeed() {
|
||||
try {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<view data-theme="{{themeMode}}">
|
||||
<button class="create-post-btn" bindtap="openCreate">+ 分享动态</button>
|
||||
|
||||
<view wx:for="{{posts}}" wx:key="id" class="post-card" wx:for-item="p">
|
||||
@@ -24,6 +25,7 @@
|
||||
<view class="modal-actions">
|
||||
<button class="cancel-btn" bindtap="closeCreate">取消</button>
|
||||
<button class="submit-btn" disabled="{{!content.trim()}}" bindtap="submitPost">发布</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
.create-post-btn { display: block; margin: 12px 16px; background: white; border-radius: 12px; padding: 16px; color: #86868B; font-size: 15px; text-align: left; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.post-card { background: white; border-radius: 12px; margin: 8px 16px; padding: 14px 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.create-post-btn { display: block; margin: 12px 16px; background: var(--color-card); border-radius: 12px; padding: 16px; color: var(--color-text-secondary); font-size: 15px; text-align: left; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.post-card { background: var(--color-card); border-radius: 12px; margin: 8px 16px; padding: 14px 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.post-header { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
|
||||
.post-avatar { width: 36px; height: 36px; border-radius: 18px; background: linear-gradient(135deg,#FF6B35,#FF4D6D); display: flex; align-items: center; justify-content: center; color: white; font-size: 14px; font-weight: 600; }
|
||||
.post-user { font-size: 14px; font-weight: 600; display: block; }
|
||||
.post-time { font-size: 12px; color: #86868B; }
|
||||
.post-content { font-size: 15px; line-height: 1.5; display: block; }
|
||||
.post-actions { display: flex; gap: 20px; padding-top: 8px; margin-top: 8px; border-top: 0.5px solid #F0F0F0; }
|
||||
.action-btn { font-size: 13px; color: #86868B; }
|
||||
.load-more { text-align: center; padding: 16px; color: #86868B; font-size: 14px; }
|
||||
.post-avatar { width: 36px; height: 36px; border-radius: 18px; background: var(--color-primary-gradient); display: flex; align-items: center; justify-content: center; color: white; font-size: 14px; font-weight: 600; }
|
||||
.post-user { font-size: 14px; font-weight: 600; display: block; color: var(--color-text); }
|
||||
.post-time { font-size: 12px; color: var(--color-text-secondary); }
|
||||
.post-content { font-size: 15px; line-height: 1.5; display: block; color: var(--color-text); }
|
||||
.post-actions { display: flex; gap: 20px; padding-top: 8px; margin-top: 8px; border-top: 0.5px solid var(--color-divider); }
|
||||
.action-btn { font-size: 13px; color: var(--color-text-secondary); }
|
||||
.load-more { text-align: center; padding: 16px; color: var(--color-text-secondary); font-size: 14px; }
|
||||
.empty { text-align: center; padding: 60px 16px; font-size: 40px; }
|
||||
.empty-text { font-size: 15px; color: #86868B; display: block; margin-top: 8px; }
|
||||
.loading { text-align: center; padding: 40px; color: #86868B; }
|
||||
.empty-text { font-size: 15px; color: var(--color-text-secondary); display: block; margin-top: 8px; }
|
||||
.loading { text-align: center; padding: 40px; color: var(--color-text-secondary); }
|
||||
|
||||
.modal-mask { position: fixed; inset: 0; background: rgba(0,0,0,0.4); display: flex; align-items: flex-end; z-index: 100; }
|
||||
.modal-content { background: white; border-radius: 16px 16px 0 0; width: 100%; padding: 20px 16px; }
|
||||
.modal-title { font-size: 17px; font-weight: 600; text-align: center; display: block; margin-bottom: 12px; }
|
||||
.modal-textarea { width: 100%; border: 1px solid #E5E5EA; border-radius: 10px; padding: 12px; font-size: 15px; min-height: 120px; box-sizing: border-box; }
|
||||
.modal-content { background: var(--color-card); border-radius: 16px 16px 0 0; width: 100%; padding: 20px 16px; }
|
||||
.modal-title { font-size: 17px; font-weight: 600; text-align: center; display: block; margin-bottom: 12px; color: var(--color-text); }
|
||||
.modal-textarea { width: 100%; border: 1px solid var(--color-border); border-radius: 10px; padding: 12px; font-size: 15px; min-height: 120px; box-sizing: border-box; background: var(--color-input-bg); color: var(--color-text); }
|
||||
.modal-actions { display: flex; gap: 12px; margin-top: 12px; }
|
||||
.cancel-btn { flex: 1; padding: 12px; background: #f8f8fa; border: 1px solid #E5E5EA; border-radius: 10px; font-size: 15px; text-align: center; }
|
||||
.submit-btn { flex: 1; padding: 12px; background: linear-gradient(135deg,#FF6B35,#FF4D6D); color: white; border: none; border-radius: 10px; font-size: 15px; font-weight: 600; text-align: center; }
|
||||
.submit-btn[disabled] { opacity: 0.5; }
|
||||
.cancel-btn { flex: 1; padding: 12px; background: var(--color-input-bg); border: 1px solid var(--color-border); border-radius: 10px; font-size: 15px; text-align: center; color: var(--color-text); }
|
||||
.submit-btn { flex: 1; padding: 12px; background: var(--color-primary-gradient); color: white; border: none; border-radius: 10px; font-size: 15px; font-weight: 600; text-align: center; }
|
||||
.submit-btn[disabled] { opacity: 0.5; }
|
||||
@@ -1,7 +1,11 @@
|
||||
const api = require('../../../services/api')
|
||||
const app = getApp()
|
||||
Page({
|
||||
data: { friends: [], addPhone: '', loading: true },
|
||||
onShow() { this.loadFriends() },
|
||||
data: { friends: [], addPhone: '', loading: true, themeMode: 'light' },
|
||||
onShow() {
|
||||
this.setData({ themeMode: app.globalData.themeMode })
|
||||
this.loadFriends()
|
||||
},
|
||||
async loadFriends() {
|
||||
try { const f = await api.get('/api/social/friends'); this.setData({ friends: f || [] }) } catch(e) {}
|
||||
this.setData({ loading: false })
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<view class="add-section">
|
||||
<input class="input-field" value="{{addPhone}}" bindinput="onPhoneInput" placeholder="输入手机号添加" style="flex:1;margin-bottom:0" />
|
||||
<button class="add-btn" bindtap="onAdd" disabled="{{!addPhone.trim()}}">添加</button>
|
||||
</view>
|
||||
<view data-theme="{{themeMode}}">
|
||||
<view class="add-section">
|
||||
<input class="input-field" value="{{addPhone}}" bindinput="onPhoneInput" placeholder="输入手机号添加" style="flex:1;margin-bottom:0" />
|
||||
<button class="add-btn" bindtap="onAdd" disabled="{{!addPhone.trim()}}">添加</button>
|
||||
</view>
|
||||
|
||||
<text class="section-title">好友列表 ({{friends.length}})</text>
|
||||
<view wx:for="{{friends}}" wx:key="id" class="friend-item">
|
||||
<view class="friend-avatar">{{item.nickname?.[0] || '?'}}</view>
|
||||
<text class="friend-name">{{item.nickname || '用户'}}</text>
|
||||
<button class="remove-btn" data-id="{{item.id}}" bindtap="onRemove">删除</button>
|
||||
<text class="section-title">好友列表 ({{friends.length}})</text>
|
||||
<view wx:for="{{friends}}" wx:key="id" class="friend-item">
|
||||
<view class="friend-avatar">{{item.nickname?.[0] || '?'}}</view>
|
||||
<text class="friend-name">{{item.nickname || '用户'}}</text>
|
||||
<button class="remove-btn" data-id="{{item.id}}" bindtap="onRemove">删除</button>
|
||||
</view>
|
||||
<view class="empty" wx:if="{{!loading && friends.length===0}}"><text class="empty-text">还没有好友</text></view>
|
||||
</view>
|
||||
<view class="empty" wx:if="{{!loading && friends.length===0}}"><text class="empty-text">还没有好友</text></view>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
.add-section { display: flex; gap: 8px; padding: 12px 16px; align-items: center; }
|
||||
.add-btn { padding: 10px 20px; background: #FF6B35; color: white; border: none; border-radius: 10px; font-size: 14px; }
|
||||
.add-btn[disabled] { background: #E5E5EA; }
|
||||
.section-title { font-size: 15px; color: #86868B; padding: 16px 16px 8px; display: block; }
|
||||
.friend-item { display: flex; align-items: center; gap: 10px; background: white; margin: 4px 16px; padding: 12px 16px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.friend-avatar { width: 36px; height: 36px; border-radius: 18px; background: linear-gradient(135deg,#FF6B35,#FF4D6D); display: flex; align-items: center; justify-content: center; color: white; font-size: 14px; font-weight: 600; }
|
||||
.friend-name { flex: 1; font-size: 15px; }
|
||||
.remove-btn { background: none; border: none; color: #FF3B30; font-size: 13px; padding: 4px 8px; }
|
||||
.add-btn { padding: 10px 20px; background: var(--color-primary); color: white; border: none; border-radius: 10px; font-size: 14px; }
|
||||
.add-btn[disabled] { background: var(--color-border); }
|
||||
.section-title { font-size: 15px; color: var(--color-text-secondary); padding: 16px 16px 8px; display: block; }
|
||||
.friend-item { display: flex; align-items: center; gap: 10px; background: var(--color-card); margin: 4px 16px; padding: 12px 16px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
|
||||
.friend-avatar { width: 36px; height: 36px; border-radius: 18px; background: var(--color-primary-gradient); display: flex; align-items: center; justify-content: center; color: white; font-size: 14px; font-weight: 600; }
|
||||
.friend-name { flex: 1; font-size: 15px; color: var(--color-text); }
|
||||
.remove-btn { background: none; border: none; color: var(--color-error); font-size: 13px; padding: 4px 8px; }
|
||||
.empty { text-align: center; padding: 40px; }
|
||||
.empty-text { font-size: 15px; color: #86868B; }
|
||||
.empty-text { font-size: 15px; color: var(--color-text-secondary); }
|
||||
Reference in New Issue
Block a user