For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 重新设计家庭管理员页面,改为温暖家庭风的卡片式布局,"添加"和"邀请"改为底部固定按钮,邀请直接弹出海报。
Architecture: 单页面重写 pages/profile-extra/family-members.vue,移除齿轮设置弹窗、筛选标签、行内三维评分条,新增暖橙渐变头部、卡片式成员列表、底部固定操作栏,邀请流程直接调用 generateFamilyInviteQrCode 后弹出 SharePoster。
Tech Stack: uni-app Vue 2 Options API,微信小程序
参考设计文档: docs/superpowers/specs/2026-07-31-family-members-redesign.md
?.(用 && 替代):key 表达式(用方法调用替代)#F97316 / 米白 #FFFCF5 / 暖灰 #F5F0EB| 文件 | 操作 | 说明 |
|---|---|---|
pages/profile-extra/family-members.vue |
重写 | 完整替换模板/脚本/样式 |
components/SharePoster.vue |
无变更 | 保持现有,直接调用 |
Files:
pages/profile-extra/family-members.vue (template section)Interfaces:
members (Array), filteredMembers (computed→直接返回 members), familyName (String), loading (Boolean)Produces: 渲染完整的页面结构(头部、成员列表、空状态、底部栏)
[ ] Step 1: 替换 <template> 头部
替换现有头部(紫色渐变 + 齿轮图标)为暖橙渐变头部:
<!-- ===== 家庭信息头部 ===== -->
<view class="family-header">
<view class="family-header-content">
<text class="family-header-icon">🏠</text>
<view class="family-header-text">
<text class="family-name">{{ familyName || '我的家庭' }}</text>
<text class="family-member-count">{{ members.length }} 位成员</text>
</view>
</view>
</view>
移除筛选标签和行内三维评分条,改为纯卡片:
<!-- ===== 成员卡片列表 ===== -->
<view class="member-list">
<view class="member-card" v-for="(m, i) in filteredMembers" :key="getMemberKey(m, i)" @click="showMemberDetail(m)">
<image class="member-avatar" :src="m.avatar || '/static/default-avatar.png'" mode="aspectFill"></image>
<view class="member-info">
<text class="member-name">{{ m.nickname || '未设置' }}</text>
<text class="member-role-tag">{{ m.relativeLabel || m.roleLabel || (m.effectiveRole === 'parent' ? '家长' : '孩子') }}</text>
</view>
<text class="member-arrow">›</text>
</view>
</view>
[ ] Step 3: 替换空状态
<!-- ===== 空状态 ===== -->
<view v-if="members.length === 0" class="empty-state">
<text class="empty-icon">👨👩👧👦</text>
<text class="empty-title">还没有家庭成员</text>
<text class="empty-desc">邀请家人加入,一起记录成长</text>
<button class="empty-invite-btn" @click="onInvite">📨 邀请家人</button>
</view>
[ ] Step 4: 添加底部固定栏
<!-- ===== 底部操作栏 ===== -->
<view class="bottom-bar">
<button class="bottom-btn btn-add" @click="onAddMember">+ 添加成员</button>
<button class="bottom-btn btn-invite" @click="onInvite">📨 邀请成员</button>
</view>
[ ] Step 5: 保留成员详情弹窗模板(简化关闭按钮)
保留 member-detail-card 弹窗,仅微调视觉(去掉原来紫色相关样式,改为暖橙风格)。移除 showSettings 和 showInviteCard 相关弹窗。
[ ] Step 6: 保留 SharePoster 引用
<SharePoster :show="showPoster" :referralCode="inviteCode" :qrCodeBase64="inviteQrCode" :nickname="userNickname" :userAvatar="userAvatar" @close="showPoster = false" />
Files:
pages/profile-extra/family-members.vue (script section)Interfaces:
listFamilyMembers, switchToFamilyMember, kickFamilyMemberById, generateFamilyInviteQrCode, getFamilyMembers, updateFamilyMember from api.jsProduces: 所有页面交互逻辑
[ ] Step 1: 精简 imports 和 data
移除 showSettings, showInviteCard 相关字段。保留 showPoster, showMemberDetailModal, detailMember, memberScores 等。
import {
listFamilyMembers,
switchToFamilyMember,
kickFamilyMemberById,
generateFamilyInviteQrCode,
getFamilyMembers,
updateFamilyMember
} from '../../utils/api.js'
import store from '../../store/index.js'
import SharePoster from '@/components/SharePoster.vue'
export default {
components: { SharePoster },
data() {
return {
userId: 0, familyId: 0, familyName: '', inviteCode: '', inviteQrCode: '',
creatorId: null, members: [], isAdmin: false, loading: false,
showPoster: false, showMemberDetailModal: false, detailMember: null,
memberScores: {}, userNickname: '', userAvatar: ''
}
},
移除 filteredMembers 的筛选逻辑(直接返回 members),移除 detailMemberScores(保留,因为详情弹窗仍显示评分)。
computed: {
filteredMembers() {
return this.members // 无筛选标签,直接返回全部
},
detailMemberScores() {
if (!this.detailMember) return {}
return this.memberScores[this.detailMember.id] || {}
}
},
[ ] Step 3: 重写 onInvite 方法 — 直接弹出海报
async onInvite() {
this.inviteQrCode = ''
this.inviteCode = ''
uni.showLoading({ title: '生成邀请...' })
try {
var res = await generateFamilyInviteQrCode()
if (res.code === 200 && res.data) {
this.inviteCode = res.data.inviteCode
this.inviteQrCode = res.data.qrCodeBase64
this.showPoster = true
} else {
uni.showToast({ title: res.message || '生成失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '生成失败', icon: 'none' })
} finally {
uni.hideLoading()
}
},
[ ] Step 4: 移除 onAddMember 中的 showSettings = false
onAddMember() {
uni.navigateTo({ url: '/pages/family/add-member' })
},
[ ] Step 5: 保留其他方法不变
保留:loadMembers, buildScoreMap, loadFamilyInfo, showMemberDetail, canEditMember, onSwitchMember, confirmKick, onKickMember, onCopyCode, shareInviteCard, onEditRelation, doQuestionnaire, recordInteraction
移除:onInvite 旧实现(已替换)
Files:
pages/profile-extra/family-members.vue (style section)Interfaces:
Produces: 温暖家庭风视觉风格
[ ] Step 1: 重写全局容器样式
.container {
padding: 30rpx 30rpx 140rpx;
min-height: 100vh;
background: #F5F0EB;
}
[ ] Step 2: 暖橙渐变头部
.family-header {
background: linear-gradient(135deg, #F97316, #EA580C);
border-radius: 20rpx;
padding: 36rpx 30rpx;
margin-bottom: 24rpx;
color: #fff;
text-align: center;
}
.family-header-content { display: flex; align-items: center; justify-content: center; flex-direction: column; }
.family-header-icon { font-size: 48rpx; margin-bottom: 8rpx; }
.family-header-text { text-align: center; }
.family-name { font-size: 36rpx; font-weight: bold; display: block; }
.family-member-count { font-size: 24rpx; opacity: 0.85; margin-top: 4rpx; display: block; }
[ ] Step 3: 成员卡片样式
.member-card {
display: flex;
align-items: center;
background: #fff;
border-radius: 16rpx;
padding: 24rpx 28rpx;
margin-bottom: 16rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
.member-card:active { background: #FFFCF5; }
.member-avatar { width: 80rpx; height: 80rpx; border-radius: 50%; margin-right: 20rpx; background: #f0f0f0; flex-shrink: 0; }
.member-info { flex: 1; min-width: 0; }
.member-name { font-size: 30rpx; font-weight: 600; display: block; color: #333; }
.member-role-tag { display: inline-block; font-size: 22rpx; color: #F97316; background: #FFF7ED; padding: 4rpx 14rpx; border-radius: 8rpx; margin-top: 6rpx; }
.member-arrow { font-size: 36rpx; color: #ccc; margin-left: 12rpx; flex-shrink: 0; }
[ ] Step 4: 空状态样式
.empty-state { text-align: center; padding: 100rpx 30rpx; }
.empty-icon { font-size: 100rpx; display: block; margin-bottom: 20rpx; }
.empty-title { font-size: 32rpx; color: #666; display: block; margin-bottom: 12rpx; }
.empty-desc { font-size: 26rpx; color: #999; display: block; margin-bottom: 40rpx; }
.empty-invite-btn { background: linear-gradient(135deg, #F97316, #EA580C); color: #fff; border: none; border-radius: 40rpx; padding: 20rpx 50rpx; font-size: 28rpx; }
[ ] Step 5: 底部固定栏样式
.bottom-bar {
position: fixed;
left: 0; right: 0; bottom: 0;
padding: 16rpx 30rpx calc(16rpx + constant(safe-area-inset-bottom));
padding: 16rpx 30rpx calc(16rpx + env(safe-area-inset-bottom));
background: #fff;
display: flex;
gap: 20rpx;
box-shadow: 0 -2rpx 12rpx rgba(0,0,0,0.06);
z-index: 50;
}
.bottom-btn {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
font-size: 28rpx;
text-align: center;
border: none;
}
.bottom-btn:active { opacity: 0.85; }
.btn-add { background: #fff; color: #F97316; border: 2rpx solid #F97316; }
.btn-invite { background: linear-gradient(135deg, #F97316, #EA580C); color: #fff; }
[ ] Step 6: 更新成员详情弹窗样式暖色风
将详情弹窗中紫色 #667eea 替换为暖橙 #F97316,保留原有布局和功能按钮样式,将 .action-switch 等按钮颜色微调为暖色调。
移除不再使用的样式:.filter-tabs, .filter-tab, .settings-card, .settings-header, .settings-body, .settings-item, .invite-card, .invite-qr-wrap, .invite-code-section, .invite-actions, .member-quality-scores, .score-item, .member-source-tag, .member-extra
Files:
Verify: pages/profile-extra/family-members.vue
[ ] Step 1: 编译验证
cd /app/cfc/cfc-frontend && npm run build:mp-weixin 2>&1 | tail -20
[ ] Step 2: 最终检查
检查是否满足所有需求: