Просмотр исходного кода

docs: 家庭成员关系条关系展示增强设计文档

Sisyphus 1 месяц назад
Родитель
Сommit
fd917dcec5
1 измененных файлов с 192 добавлено и 0 удалено
  1. 192 0
      docs/superpowers/specs/2026-08-05-family-relationship-strip-design.md

+ 192 - 0
docs/superpowers/specs/2026-08-05-family-relationship-strip-design.md

@@ -0,0 +1,192 @@
+# 家庭成员关系条(FamilyMemberStrip)关系展示增强设计
+
+日期: 2026-08-05
+状态: 已确认
+关联组件: `cfc-frontend/components/FamilyMemberStrip.vue`, `cfc-frontend/components/FamilyMemberCard.vue`
+
+## 1. 背景与目标
+
+### 1.1 现状问题
+
+`FamilyMemberStrip` 是水平成员选择条(8 个页面共用),目前每个成员卡片只显示:
+- 头像 + 关系徽章(关系类型文本,如"爸爸"/"妈妈"/"儿子")
+- 昵称、辈分、电话、能量分、配偶标记
+
+**缺失**:关系质量信息(信任度/亲密度/沟通质量)完全没有呈现。
+
+### 1.2 数据现状(关键约束)
+
+| 数据 | 现状 | 位置 |
+|------|------|------|
+| 关系类型(pairwise) | ✅ 已有 | `family_relationships` 表:from→to + generation_value + relationship_key,双向各一条 |
+| 信任/亲密度/沟通评分 | ⚠️ 仅单成员维度 | `family_members.trust_score/intimacy_score/communication_score`——本质是问卷答卷人(当前用户)对该成员的评分(`RelationshipQuestionnaireService.updateMemberScores` 写入) |
+| 问卷答卷 | ✅ pairwise 天然成立 | `relationship_questionnaire_responses`:respondent_id → snapshot_id → family_member_id |
+
+### 1.3 目标
+
+1. **卡片上直接呈现**"当前用户与该成员"的关系类型 + 关系现状(信任/亲密度/沟通),无需交互
+2. **成员详情页**以任意成员为中心,复用本组件展示该成员与所有其他成员的关系
+3. **长按操作菜单**升级为带关系现状区块的 Action Sheet,视觉更精致
+4. **未创建家庭**时显示引导(提示 + 创建家庭按钮);**当前用户菜单**增加"添加成员/邀请成员"入口
+
+### 1.4 非目标
+
+- 不改动 `FamilyRelationGraph`(力导向关系图保持现状,作为可选全景视图)
+- 不在卡片间画连线(成员多时视觉混乱,经确认放弃连线方案)
+- 不改变 8 处现有 `FamilyMemberStrip` 调用方式(默认视角零改动)
+
+## 2. 数据层设计(后端)
+
+### 2.1 `family_relationships` 表扩展评分列
+
+在 `family_members` 单成员评分之外,将评分落库到 pairwise 关系表,支撑"以任意成员为中心"的视角。
+
+```sql
+ALTER TABLE family_relationships
+  ADD COLUMN trust_score DECIMAL(5,2) DEFAULT 0 COMMENT '信任度(答卷人视角)',
+  ADD COLUMN intimacy_score DECIMAL(5,2) DEFAULT 0 COMMENT '亲密度(答卷人视角)',
+  ADD COLUMN communication_score DECIMAL(5,2) DEFAULT 0 COMMENT '沟通质量(答卷人视角)';
+```
+
+- **迁移入口**: `DatabaseInitializer.runMigrations()` 使用 `ensureColumn()`,幂等
+- **同步**: `schema.sql` 的 `family_relationships` CREATE TABLE 补三列(编号递增,搜索 `// 迁移` 确认最新号)
+- **实体**: `FamilyRelationship.java` 增加三个 `BigDecimal` 字段
+
+### 2.2 问卷写入同步到 pairwise 表
+
+`RelationshipQuestionnaireService.updateMemberScores(Long memberId, BigDecimal[] scores)` 增加逻辑:
+1. 通过 `memberId` 找到被评成员(to_member_id)
+2. 通过答卷人(respondent)定位其 family_member_id(from_member_id);若答卷人无 family_member 记录则跳过(不阻塞主流程)
+3. 存在 `family_relationships` 行则更新三列评分;不存在则插入新行(generation_value 从双方成员 generation 计算)
+4. 保持事务内,失败仅记日志不阻断问卷保存
+
+### 2.3 新增 pairwise 接口
+
+```
+POST /api/family/relationship/pairwise
+入参: { "centerMemberId": 123 }   // 可选,空 = 当前用户视角
+出参: Result<List<FamilyMemberVO>>  // 以 centerMember 为中心的关系列表
+```
+
+- **Controller**: `RelationshipQualityController` 新增 `pairwise` 方法(`@PostMapping`)
+- **Service**: `RelationshipQualityService` 新增 `getPairwiseRelationships(Long centerMemberId, Long familyId)`:
+  - 查 family_relationships 中 `from_member_id = centerMemberId` 的所有行
+  - join family_members 取目标成员资料(昵称/头像/性别/手机号/generation)
+  - 关系标签:优先 `relationship_key` → 否则用 `FamilyRelationshipService.computeRelationshipLabel(generationValue, gender)`
+  - 评分:取该行的 trust/intimacy/communication(无记录默认 0)
+  - 复用 `FamilyMemberVO` 结构返回(含 `isSelf` 标记 centerMember 自身)
+
+### 2.4 家庭是否存在判定
+
+前端通过 `getVisibleFamilyMembers` 的返回判定:接口返回空数组 = 无家庭或家庭成员不可见 → 显示"创建家庭"引导。
+
+## 3. 前端设计
+
+### 3.1 FamilyMemberCard 徽章区(无需交互,直接可见)
+
+关系徽章下方增加三个迷你圆点(关系现状指示):
+
+```
+[ 爸爸 ]        ← 关系类型徽章(现有,配色保留)
+● ● ●          ← 三个圆点:信任/亲密度/沟通
+```
+
+- 颜色分级:绿 `#10B981`(≥70)/ 黄 `#F59E0B`(40-69)/ 红 `#EF4444`(<40)
+- 三圆点含义需可辨识 → 增加极小的下划线/序号辅助?**不做**(空间有限,色点语义在长按菜单中解释)
+- 空数据(全 0 或未测评)→ 显示灰色 `· · ·`
+- 数据源:`member.trustScore/intimacyScore/communicationScore`(FamilyMemberVO 已有字段,当前用户视角)
+- 卡片宽度 140rpx 不变,色点放在徽章正下方 2rpx 处,直径 12rpx
+
+### 3.2 FamilyMemberStrip 空状态引导
+
+当前模板 `v-if="members && members.length > 0"` 空时整条不渲染 → 增加 `v-else` 分支:
+
+```
+┌─────────────────────────────┐
+│  🏠 还未创建家庭             │
+│  创建家庭,开启全家幸福之旅    │
+│  [+ 创建家庭]               │
+└─────────────────────────────┘
+```
+
+- 按钮 `@click` 调 `createFamily(nickname + '的家庭')`(复用 `utils/api.js` 的 `createFamily`,参照 `user-edit.vue` 的 `createFamilyAction`)
+- 创建成功后 `$emit('created')`,父组件刷新成员列表
+
+### 3.3 长按操作菜单(升级版 Action Sheet)
+
+**当前用户**(`member.isSelf === true`)与**其他成员**菜单不同:
+
+```
+┌─────────────────────────────────┐
+│  (头像) 小明                     │
+│         儿子 · 8岁               │
+│  ── 关系现状 ──                  │
+│  信任度   ████████ 82            │
+│  亲密度   ██████   60            │
+│  沟通质量 █████████ 91           │
+│  ───────────────                 │
+│  ➕ 添加成员                     │   ← 仅当前用户
+│  📨 邀请成员                     │   ← 仅当前用户
+│  🔄 切换到该成员视角              │   ← 非本人且有 userId
+│  ✏️ 编辑资料                     │   ← isParent 且可编辑
+│  📋 关系问卷  → 上次填写 3天前    │   ← 显示上次填写时间
+│  💬 记录互动                     │
+│  📞 拨打电话                     │   ← 有 phone
+│  🗑️ 移除成员                    │   ← isParent 且非本人
+└─────────────────────────────────┘
+```
+
+- **头部**: 头像 + 昵称 + 关系标签(`relationship || relativeLabel || roleLabel`)
+- **关系现状区块**: 三条迷你进度条(背景 `#F3F4F6`,填充色按分级),右侧数值;无数据时显示"未测评"
+- **当前用户专属**: "添加成员"(跳 `/pages/family/add-member`)、"邀请成员"(跳邀请二维码页,参照 `family-members.vue` 的 📨 邀请成员逻辑)
+- **权限控制**: 保留现有 `canSwitch/canEdit/canRemove` computed,新增 `isSelf` 判断
+- **视觉**: 圆角 24rpx、柔和阴影、分区标题(12px 灰)、图标统一 emoji、操作项 44rpx 行高、底部取消按钮
+
+### 3.4 FamilyMemberStrip 新增 `centerMemberId` prop
+
+- `centerMemberId: { type: Number, default: null }`
+- **不传(默认)**: 现有逻辑不变——父组件传 `members` 数组(当前用户视角)
+- **传入**: 组件内部拉取 pairwise 接口,`members` 由组件自身组装(以 centerMember 为中心)
+
+### 3.5 成员详情页接入
+
+`pages/home-pages/member-home-detail.vue` 增加 FamilyMemberStrip 区块:
+- 传入 `:center-member-id="memberId"`,展示"以该成员为中心"的关系条
+- 复用 3.3 的 Action Sheet(该页面的长按菜单沿用权限控制)
+
+## 4. 交互流程
+
+1. **首页/维度页加载** → `getVisibleFamilyMembers` 返回空 → 显示创建家庭引导卡
+2. **有成员** → 卡片行展示,关系徽章 + 三色点
+3. **点卡片** → 选中(`selectedMemberId`)或切换视角(沿用现有逻辑)
+4. **长按卡片** → 弹出 Action Sheet:关系现状 + 操作项
+5. **成员详情页** → 以该成员为中心的关系条(pairwise)
+
+## 5. 错误处理与边界
+
+| 场景 | 处理 |
+|------|------|
+| 无家庭/无成员 | 空状态引导卡 + 创建家庭按钮 |
+| 未填写关系问卷 | 色点灰色 `· · ·`,菜单关系区块"未测评" |
+| pairwise 接口失败 | 组件 fallback 为传入的 members 渲染(不阻塞页面) |
+| 答卷人无 family_member 记录 | 问卷保存不阻塞,日志记录 |
+| 长按非本人卡片 | 不显示添加/邀请成员 |
+| 非家长长按 | 不显示编辑/移除(现有 canEdit/canRemove 逻辑保留) |
+
+## 6. 验证
+
+- 后端: `mvn clean compile`
+- 前端: `npm run build:mp-weixin`(微信小程序编译通过)
+- 手动验证场景:
+  1. 未创建家庭用户 → 看到创建家庭引导
+  2. 已有家庭 → 卡片显示关系徽章 + 三色点
+  3. 长按自己 → 菜单含添加/邀请成员 + 关系现状
+  4. 长按其他成员 → 菜单不含添加/邀请,含切换/编辑/问卷/互动/电话/移除(按权限)
+  5. 成员详情页 → 以该成员为中心的关系条
+
+## 7. 不做的事(YAGNI)
+
+- 卡片间连线(已放弃)
+- hover 交互(小程序无 hover 事件)
+- FamilyRelationGraph 改动
+- 复杂评分算法(沿用问卷简化评分)