|
@@ -9,12 +9,55 @@
|
|
|
</view>
|
|
</view>
|
|
|
<view class="sun-icon">☀️</view>
|
|
<view class="sun-icon">☀️</view>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="child-status-card" v-if="selectedChild">
|
|
|
|
|
- <view class="child-avatar-large">{{ selectedChild.nickname ? selectedChild.nickname[0] : '?' }}</view>
|
|
|
|
|
- <view class="child-status-info">
|
|
|
|
|
- <text class="child-name">{{ selectedChild.nickname }}正在健康成长中</text>
|
|
|
|
|
- <text class="child-motto">🌱 每天进步一点点</text>
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 孩子卡片行 -->
|
|
|
|
|
+ <view class="children-row" v-if="children.length > 0">
|
|
|
|
|
+ <scroll-view
|
|
|
|
|
+ class="children-scroll"
|
|
|
|
|
+ scroll-x
|
|
|
|
|
+ :scroll-with-animation="true"
|
|
|
|
|
+ :enhanced="true"
|
|
|
|
|
+ :show-scrollbar="false"
|
|
|
|
|
+ >
|
|
|
|
|
+ <!-- 一孩时,用大卡片 -->
|
|
|
|
|
+ <view
|
|
|
|
|
+ v-for="child in children"
|
|
|
|
|
+ :key="child.id"
|
|
|
|
|
+ class="child-card"
|
|
|
|
|
+ :class="{ 'child-card-single': children.length === 1 }"
|
|
|
|
|
+ @click="goToChildDetail(child)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <view class="child-avatar" :class="'child-avatar-color-' + (child.id % 6)">
|
|
|
|
|
+ <text class="child-avatar-text">{{ child.nickname ? child.nickname[0] : '?' }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="child-card-body">
|
|
|
|
|
+ <text class="child-card-name">{{ child.nickname }}</text>
|
|
|
|
|
+ <view class="child-card-stats">
|
|
|
|
|
+ <text class="child-card-points">⭐ {{ child.totalPoints || 0 }}</text>
|
|
|
|
|
+ <text class="child-card-dan" v-if="child.danLevel">DAN: {{ child.danLevel }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="child-card-badges">
|
|
|
|
|
+ <text class="badge badge-review" v-if="child.pendingReviewCount > 0">待审 {{ child.pendingReviewCount }}</text>
|
|
|
|
|
+ <text class="badge badge-wish" v-if="child.pendingWishCount > 0">心愿 {{ child.pendingWishCount }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="child-card-arrow">›</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </scroll-view>
|
|
|
|
|
+ <!-- 多孩提示 -->
|
|
|
|
|
+ <view class="scroll-hint" v-if="children.length > 1">
|
|
|
|
|
+ <text class="scroll-hint-text">← 左右滑动查看更多 →</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 无孩子时引导 -->
|
|
|
|
|
+ <view class="empty-children-card" v-else @click="goToAddChild">
|
|
|
|
|
+ <view class="empty-children-icon">👶</view>
|
|
|
|
|
+ <view class="empty-children-text">
|
|
|
|
|
+ <text class="empty-children-title">还没有添加孩子</text>
|
|
|
|
|
+ <text class="empty-children-hint">点击添加孩子,开始成长之旅</text>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
+ <view class="empty-children-arrow">›</view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
@@ -138,10 +181,6 @@
|
|
|
<view class="action-icon reward-icon">🎁</view>
|
|
<view class="action-icon reward-icon">🎁</view>
|
|
|
<text class="action-label">奖励中心</text>
|
|
<text class="action-label">奖励中心</text>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="action-item" @click="goToGrowth">
|
|
|
|
|
- <view class="action-icon growth-icon">🌱</view>
|
|
|
|
|
- <text class="action-label">成长档案</text>
|
|
|
|
|
- </view>
|
|
|
|
|
<view class="action-item" @click="inviteFriend">
|
|
<view class="action-item" @click="inviteFriend">
|
|
|
<view class="action-icon invite-icon">📤</view>
|
|
<view class="action-icon invite-icon">📤</view>
|
|
|
<text class="action-label">邀请家人</text>
|
|
<text class="action-label">邀请家人</text>
|
|
@@ -152,7 +191,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
-import { getFamilyMembers, getChildren, getPendingReviewTasks, approveTask, rejectTask, switchToChild, switchBackToParent } from '../../utils/api.js'
|
|
|
|
|
|
|
+import { getFamilyMembers, getChildren, getPendingReviewTasks, approveTask, rejectTask, getPendingWishes } from '../../utils/api.js'
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
|
data() {
|
|
data() {
|
|
@@ -162,6 +201,7 @@ export default {
|
|
|
children: [],
|
|
children: [],
|
|
|
selectedChild: null,
|
|
selectedChild: null,
|
|
|
pendingReviewTasks: [],
|
|
pendingReviewTasks: [],
|
|
|
|
|
+ pendingReviewWishes: [],
|
|
|
pendingTasks: [],
|
|
pendingTasks: [],
|
|
|
taskCompletionRate: 85,
|
|
taskCompletionRate: 85,
|
|
|
habitCount: 3,
|
|
habitCount: 3,
|
|
@@ -220,7 +260,6 @@ export default {
|
|
|
.map(c => ({ ...c, role: 'child' }))
|
|
.map(c => ({ ...c, role: 'child' }))
|
|
|
this.familyMembers = [...parents, ...children]
|
|
this.familyMembers = [...parents, ...children]
|
|
|
|
|
|
|
|
- // 设置选中的孩子
|
|
|
|
|
if (children.length > 0) {
|
|
if (children.length > 0) {
|
|
|
this.selectedChild = children[0]
|
|
this.selectedChild = children[0]
|
|
|
}
|
|
}
|
|
@@ -228,14 +267,49 @@ export default {
|
|
|
console.log('获取家庭成员失败', e)
|
|
console.log('获取家庭成员失败', e)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 获取孩子列表
|
|
|
const childrenRes = await getChildren()
|
|
const childrenRes = await getChildren()
|
|
|
- this.children = childrenRes.data || []
|
|
|
|
|
|
|
+ const rawChildren = childrenRes.data || []
|
|
|
|
|
+ this.children = rawChildren
|
|
|
if (this.children.length > 0 && !this.selectedChild) {
|
|
if (this.children.length > 0 && !this.selectedChild) {
|
|
|
this.selectedChild = this.children[0]
|
|
this.selectedChild = this.children[0]
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 获取待审核任务
|
|
|
const reviewRes = await getPendingReviewTasks()
|
|
const reviewRes = await getPendingReviewTasks()
|
|
|
- this.pendingReviewTasks = (reviewRes.data || []).slice(0, 3)
|
|
|
|
|
|
|
+ const allReviewTasks = reviewRes.data || []
|
|
|
|
|
+ this.pendingReviewTasks = allReviewTasks.slice(0, 3)
|
|
|
|
|
+
|
|
|
|
|
+ // 获取待处理心愿
|
|
|
|
|
+ try {
|
|
|
|
|
+ const wishRes = await getPendingWishes()
|
|
|
|
|
+ this.pendingReviewWishes = wishRes.data || []
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.log('获取待处理心愿失败', e)
|
|
|
|
|
+ this.pendingReviewWishes = []
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 为每个孩子计算待处理数量
|
|
|
|
|
+ const reviewMap = {}
|
|
|
|
|
+ const wishMap = {}
|
|
|
|
|
+ for (const task of allReviewTasks) {
|
|
|
|
|
+ const cid = task.childId || task.assigneeId
|
|
|
|
|
+ if (cid) {
|
|
|
|
|
+ reviewMap[cid] = (reviewMap[cid] || 0) + 1
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ for (const wish of (this.pendingReviewWishes || [])) {
|
|
|
|
|
+ const cid = wish.childId
|
|
|
|
|
+ if (cid) {
|
|
|
|
|
+ wishMap[cid] = (wishMap[cid] || 0) + 1
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 在 children 对象上附加待处理计数
|
|
|
|
|
+ this.children = this.children.map(c => ({
|
|
|
|
|
+ ...c,
|
|
|
|
|
+ pendingReviewCount: reviewMap[c.id] || 0,
|
|
|
|
|
+ pendingWishCount: wishMap[c.id] || 0
|
|
|
|
|
+ }))
|
|
|
|
|
|
|
|
// 模拟待完成任务数据
|
|
// 模拟待完成任务数据
|
|
|
this.pendingTasks = [
|
|
this.pendingTasks = [
|
|
@@ -268,6 +342,11 @@ export default {
|
|
|
uni.showToast({ title: '操作失败', icon: 'none' })
|
|
uni.showToast({ title: '操作失败', icon: 'none' })
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
+ goToChildDetail(child) {
|
|
|
|
|
+ uni.navigateTo({
|
|
|
|
|
+ url: '/pages/parent/child-detail?childId=' + child.id + '&childName=' + encodeURIComponent(child.nickname || '')
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
addTask() {
|
|
addTask() {
|
|
|
uni.navigateTo({ url: '/pages/tasks/create-task' })
|
|
uni.navigateTo({ url: '/pages/tasks/create-task' })
|
|
|
},
|
|
},
|
|
@@ -286,8 +365,8 @@ export default {
|
|
|
inviteFriend() {
|
|
inviteFriend() {
|
|
|
uni.navigateTo({ url: '/pages/parent/invite/index' })
|
|
uni.navigateTo({ url: '/pages/parent/invite/index' })
|
|
|
},
|
|
},
|
|
|
- goToGrowth() {
|
|
|
|
|
- uni.navigateTo({ url: '/pages/growth/index' })
|
|
|
|
|
|
|
+ goToAddChild() {
|
|
|
|
|
+ uni.navigateTo({ url: '/pages/profile/create-child' })
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -332,44 +411,170 @@ export default {
|
|
|
font-size: 64rpx;
|
|
font-size: 64rpx;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.child-status-card {
|
|
|
|
|
|
|
+/* 孩子卡片行 */
|
|
|
|
|
+.children-row {
|
|
|
|
|
+ margin-top: 24rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.children-scroll {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
|
|
+ flex-direction: row;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.child-card {
|
|
|
|
|
+ display: inline-flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
background: #FFFFFF;
|
|
background: #FFFFFF;
|
|
|
- border-radius: 24rpx;
|
|
|
|
|
- padding: 24rpx;
|
|
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+ padding: 20rpx 24rpx;
|
|
|
|
|
+ margin-right: 20rpx;
|
|
|
box-shadow: 0 4px 20px rgba(255, 140, 66, 0.08);
|
|
box-shadow: 0 4px 20px rgba(255, 140, 66, 0.08);
|
|
|
|
|
+ min-width: 440rpx;
|
|
|
|
|
+ width: auto;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.child-card-single {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ margin-right: 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.child-avatar-large {
|
|
|
|
|
- width: 96rpx;
|
|
|
|
|
- height: 96rpx;
|
|
|
|
|
|
|
+.child-avatar {
|
|
|
|
|
+ width: 80rpx;
|
|
|
|
|
+ height: 80rpx;
|
|
|
border-radius: 50%;
|
|
border-radius: 50%;
|
|
|
- background: linear-gradient(135deg, #FF8C42, #FF7A2E);
|
|
|
|
|
- color: #FFFFFF;
|
|
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
justify-content: center;
|
|
|
- font-size: 40rpx;
|
|
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.child-avatar-color-0 { background: linear-gradient(135deg, #FF8C42, #FF7A2E); }
|
|
|
|
|
+.child-avatar-color-1 { background: linear-gradient(135deg, #667eea, #764ba2); }
|
|
|
|
|
+.child-avatar-color-2 { background: linear-gradient(135deg, #4ECDC4, #44B09E); }
|
|
|
|
|
+.child-avatar-color-3 { background: linear-gradient(135deg, #FF6B6B, #FF8E53); }
|
|
|
|
|
+.child-avatar-color-4 { background: linear-gradient(135deg, #A8E063, #56AB2F); }
|
|
|
|
|
+.child-avatar-color-5 { background: linear-gradient(135deg, #F093FB, #F5576C); }
|
|
|
|
|
+
|
|
|
|
|
+.child-avatar-text {
|
|
|
|
|
+ color: #FFFFFF;
|
|
|
|
|
+ font-size: 36rpx;
|
|
|
font-weight: 600;
|
|
font-weight: 600;
|
|
|
- margin-right: 24rpx;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.child-status-info {
|
|
|
|
|
|
|
+.child-card-body {
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
|
|
+ margin-left: 16rpx;
|
|
|
|
|
+ min-width: 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.child-status-info .child-name {
|
|
|
|
|
- font-size: 28rpx;
|
|
|
|
|
|
|
+.child-card-name {
|
|
|
|
|
+ font-size: 30rpx;
|
|
|
font-weight: 600;
|
|
font-weight: 600;
|
|
|
color: #2D3436;
|
|
color: #2D3436;
|
|
|
display: block;
|
|
display: block;
|
|
|
|
|
+ line-height: 1.3;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.child-card-stats {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-top: 6rpx;
|
|
|
|
|
+ gap: 16rpx;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.child-status-info .child-motto {
|
|
|
|
|
|
|
+.child-card-points {
|
|
|
font-size: 24rpx;
|
|
font-size: 24rpx;
|
|
|
- color: #4ECDC4;
|
|
|
|
|
|
|
+ color: #FF8C42;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.child-card-dan {
|
|
|
|
|
+ font-size: 22rpx;
|
|
|
|
|
+ color: #667eea;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.child-card-badges {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 8rpx;
|
|
|
margin-top: 8rpx;
|
|
margin-top: 8rpx;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.badge {
|
|
|
|
|
+ font-size: 20rpx;
|
|
|
|
|
+ padding: 4rpx 12rpx;
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.badge-review {
|
|
|
|
|
+ background: #FFF5EB;
|
|
|
|
|
+ color: #FF8C42;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.badge-wish {
|
|
|
|
|
+ background: #FFF0F0;
|
|
|
|
|
+ color: #FF6B6B;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.child-card-arrow {
|
|
|
|
|
+ font-size: 36rpx;
|
|
|
|
|
+ color: #D5D5D5;
|
|
|
|
|
+ margin-left: 8rpx;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.scroll-hint {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ margin-top: 12rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.scroll-hint-text {
|
|
|
|
|
+ font-size: 22rpx;
|
|
|
|
|
+ color: #B2BEC3;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 无孩子引导 */
|
|
|
|
|
+.empty-children-card {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ background: #FFFFFF;
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+ padding: 24rpx;
|
|
|
|
|
+ box-shadow: 0 4px 20px rgba(255, 140, 66, 0.08);
|
|
|
|
|
+ margin-top: 24rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-children-icon {
|
|
|
|
|
+ font-size: 56rpx;
|
|
|
|
|
+ margin-right: 16rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-children-text {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-children-title {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #2D3436;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-children-hint {
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #B2BEC3;
|
|
|
|
|
+ margin-top: 6rpx;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-children-arrow {
|
|
|
|
|
+ font-size: 36rpx;
|
|
|
|
|
+ color: #D5D5D5;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* 区块标题 */
|
|
/* 区块标题 */
|
|
@@ -705,10 +910,6 @@ export default {
|
|
|
background: rgba(0, 184, 148, 0.15);
|
|
background: rgba(0, 184, 148, 0.15);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.growth-icon {
|
|
|
|
|
- background: rgba(78, 205, 196, 0.15);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
.action-label {
|
|
.action-label {
|
|
|
font-size: 24rpx;
|
|
font-size: 24rpx;
|
|
|
color: #636E72;
|
|
color: #636E72;
|