用户使用流程图 — 圈子与联系人
端口说明: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
分层说明: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
flowchart TD
%% ============ 颜色定义 ============
classDef page fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef api fill:#fff3e0,stroke:#f57c00,stroke-width:1px
classDef service fill:#e8f5e9,stroke:#388e3c,stroke-width:1px
classDef data fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1px
classDef external fill:#fce4ec,stroke:#d32f2f,stroke-width:1px,stroke-dasharray:3 2
classDef actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
%% ============ 角色 ============
ROLE_PARENT(("👤 家长")):::actor
ROLE_CHILD(("👶 孩子")):::actor
%% ================================================================
%% 阶段一:社交圈子管理
%% ================================================================
subgraph 阶段一[阶段一:社交圈子管理]
direction TB
P1["🏠 小程序:圈子列表页"]:::page
P1 -->|"选择操作"| P1_choice{"查看 / 发现 / 创建"}:::page
P1_choice -->|"查看我的圈子"| A1["🔗 POST /api/circle/my-circles"]:::api
A1 -->|"memberId, memberType"| S1["⚙️ CircleService.getMyCircles()"]:::service
S1 -->|"查询成员关系后关联圈子信息"| D1["📦 social_circle_member + social_circle"]:::data
P1_choice -->|"发现推荐圈子"| P1a["🏠 小程序:发现圈子页"]:::page
P1a -->|"childId"| A2["🔗 POST /api/circle/discover"]:::api
A2 -->|"childId"| S2["⚙️ CircleService.discoverCircles()"]:::service
S2 -->|"调用匹配引擎, 过滤已加入"| S2a["⚙️ CircleMatchService.discover()"]:::service
S2a -->|"活动/测评/健康报告等匹配源"| D1a["📦 匹配结果(内存中)"]:::data
P1_choice -->|"创建圈子"| P1b["🏠 小程序:创建圈子表单"]:::page
P1b -->|"name, type, matchSource, creatorId, creatorType"| A3["🔗 POST /api/circle/create"]:::api
A3 -->|"圈子基本信息"| S3["⚙️ CircleService.createCircle()"]:::service
S3 -->|"写入圈子记录, 创建者自动加入"| D1b["📦 social_circle + social_circle_member"]:::data
D1 -->|"circleId"| P1c["🏠 小程序:圈子详情页"]:::page
P1c -->|"加入圈子"| A4["🔗 POST /api/circle/join"]:::api
A4 -->|"circleId, memberId, memberType"| S4["⚙️ CircleService.joinCircle()"]:::service
S4 -->|"写成员记录, 更新成员计数"| D1c["📦 social_circle_member + social_circle"]:::data
P1c -->|"退出圈子"| A5["🔗 POST /api/circle/leave"]:::api
A5 -->|"circleId, memberId, memberType"| S5["⚙️ CircleService.leaveCircle()"]:::service
S5 -->|"删除成员记录, 更新成员计数"| D1
end
%% ================================================================
%% 阶段二:健康圈子
%% ================================================================
subgraph 阶段二[阶段二:健康圈子]
direction TB
P2["🏠 小程序:健康圈子页"]:::page
P2 -->|"选择操作"| P2_choice{"列表 / 创建 / 加入 / 退出 / 排行"}:::page
P2_choice -->|"列表"| A6["🔗 POST /api/health/circle/list"]:::api
A6 -->|"familyId"| S6["⚙️ HealthCircleService.getUserCircles()"]:::service
S6 -->|"查询家庭所属的健康圈"| D2["📦 health_circle"]:::data
P2_choice -->|"创建"| P2a["🏠 小程序:创建健康圈子表单"]:::page
P2a -->|"name, description, familyId"| A7["🔗 POST /api/health/circle/create"]:::api
A7 -->|"圈子名称, 描述, 所属家庭"| S7["⚙️ HealthCircleService.createCircle()"]:::service
S7 -->|"写入健康圈记录, 生成邀请码"| D2a["📦 health_circle"]:::data
P2_choice -->|"加入"| P2b["🏠 小程序:输入邀请码"]:::page
P2b -->|"inviteCode, familyId"| A8["🔗 POST /api/health/circle/join"]:::api
A8 -->|"邀请码, 家庭ID"| S8["⚙️ HealthCircleService.joinCircle()"]:::service
S8 -->|"校验邀请码, 写入成员记录"| D2b["📦 health_circle_member"]:::data
P2_choice -->|"退出"| P2c["🏠 小程序:确认退出"]:::page
P2c -->|"circleId, familyId"| A9["🔗 POST /api/health/circle/leave"]:::api
A9 -->|"圈ID, 家庭ID"| S9["⚙️ HealthCircleService.leaveCircle()"]:::service
S9 -->|"标记成员退出"| D2b
P2_choice -->|"排行"| P2d["🏠 小程序:健康圈排行榜"]:::page
P2d -->|"circleId"| A10["🔗 POST /api/health/circle/ranking"]:::api
A10 -->|"圈ID"| S10["⚙️ HealthCircleService.getCircleRanking()"]:::service
S10 -->|"各家庭健康积分排行"| D2c["📦 排行数据(内存)"]:::data
end
%% ================================================================
%% 阶段三:挑战
%% ================================================================
subgraph 阶段三[阶段三:挑战管理]
direction TB
D2 -->|"circleId"| P3["🏠 小程序:圈子挑战页"]:::page
P3 -->|"查看挑战列表"| A11["🔗 POST /api/health/circle/challenge/list"]:::api
A11 -->|"circleId"| S11["⚙️ CircleChallengeService.getActiveChallenges()"]:::service
S11 -->|"该圈子活跃的挑战"| D3["📦 circle_challenge"]:::data
P3 -->|"查看挑战历史"| A12["🔗 POST /api/health/circle/challenge/history"]:::api
A12 -->|"circleId"| S12["⚙️ CircleChallengeService.getChallengeHistory()"]:::service
S12 -->|"该圈子已完成的挑战"| D3
P3a["🏠 小程序:家庭挑战页"]:::page
P3a -->|"查看家庭挑战"| A13["🔗 POST /api/health/challenge/list"]:::api
A13 -->|"familyId"| S13["⚙️ FamilyChallengeService.getActiveChallenges()"]:::service
S13 -->|"该家庭活跃的挑战"| D3a["📦 family_challenge"]:::data
P3a -->|"查看挑战历史"| A14["🔗 POST /api/health/challenge/history"]:::api
A14 -->|"familyId"| S14["⚙️ FamilyChallengeService.getChallengeHistory()"]:::service
S14 -->|"该家庭已完成的挑战"| D3a
P3a -->|"更新挑战进度"| P3b["🏠 小程序:执行挑战任务"]:::page
P3b -->|"challengeId, childId, delta"| A15["🔗 POST /api/health/challenge/progress"]:::api
A15 -->|"挑战ID, 孩子ID, 进度增量"| S15["⚙️ FamilyChallengeService.updateProgress()"]:::service
S15 -->|"更新进度, 自动完成检测"| D3a
end
%% ================================================================
%% 阶段四:联系人管理
%% ================================================================
subgraph 阶段四[阶段四:联系人管理]
direction TB
P4["🏠 小程序:联系人列表页"]:::page
P4 -->|"选择操作"| P4_choice{"列表 / 创建 / 导入 / 详情"}:::page
P4_choice -->|"查看列表"| A16["🔗 POST /api/contact/list"]:::api
A16 -->|"userId(从token提取)"| S16["⚙️ ContactService.list()"]:::service
S16 -->|"按亲密度降序排列"| D4["📦 contacts 表"]:::data
P4_choice -->|"手动创建"| P4a["🏠 小程序:新建联系人表单"]:::page
P4a -->|"name, phone, relationshipType, ..."| A17["🔗 POST /api/contact/create"]:::api
A17 -->|"联系人基本信息"| S17["⚙️ ContactService.create()"]:::service
S17 -->|"写入联系人, 默认亲密度30"| D4
P4_choice -->|"导入手机联系人"| P4b["🏠 小程序:手机联系人列表"]:::page
P4b -->|"name, phone, extra信息"| A18["🔗 POST /api/contact/import-phone"]:::api
A18 -->|"姓名, 手机号, 额外信息"| S18["⚙️ ContactService.importFromPhone()"]:::service
S18 -->|"去重后写入, 来源标记phone"| D4
D4 -->|"contactId"| P4c["🏠 小程序:联系人详情页"]:::page
P4c -->|"查看详情"| A19["🔗 POST /api/contact/detail"]:::api
A19 -->|"id"| S19["⚙️ ContactService.detail()"]:::service
S19 -->|"返回DTO(含生日倒计时等)"| D4
P4c -->|"编辑联系人"| P4d["🏠 小程序:编辑联系人表单"]:::page
P4d -->|"id, name, phone, tags, ..."| A20["🔗 POST /api/contact/update"]:::api
A20 -->|"更新字段"| S20["⚙️ ContactService.update()"]:::service
S20 -->|"局部更新联系人"| D4
P4c -->|"删除联系人"| P4e["🏠 小程序:确认删除"]:::page
P4e -->|"id"| A21["🔗 POST /api/contact/delete"]:::api
A21 -->|"联系人ID"| S21["⚙️ ContactService.delete()"]:::service
S21 -->|"物理删除联系人"| D4
P4c -->|"记录互动"| A22["🔗 POST /api/contact/interaction"]:::api
A22 -->|"id"| S22["⚙️ ContactService.recordInteraction()"]:::service
S22 -->|"互动+1, 更新亲密度, 更新时间"| D4
P4c -->|"邀请到家庭"| P4f["🏠 小程序:选择关系类型"]:::page
P4f -->|"contactId, relationshipType, generationLevel"| A23["🔗 POST /api/contact/invite-to-family"]:::api
A23 -->|"联系人ID, 关系类型, 辈分"| S23["⚙️ ContactService.inviteToFamily()"]:::service
S23 -->|"标记邀请状态invited"| D4
end
%% ================================================================
%% 角色关联
%% ================================================================
ROLE_CHILD -.- P1
ROLE_CHILD -.- P1a
ROLE_CHILD -.- P3
ROLE_PARENT -.- P2
ROLE_PARENT -.- P3a
ROLE_PARENT -.- P4
端点明细
社交圈子
| 端点 |
说明 |
端口 |
请求数据 |
响应数据 |
POST /api/circle/my-circles |
获取我的圈子列表 |
📱小程序 |
{memberId, memberType} |
[{id, name, type, matchSource, memberCount}] |
POST /api/circle/discover |
发现推荐圈子 |
📱小程序 |
{childId} |
[{id, name, type, matchSource, memberCount}] |
POST /api/circle/join |
加入圈子 |
📱小程序 |
{circleId, memberId, memberType} |
{success} |
POST /api/circle/leave |
退出圈子 |
📱小程序 |
{circleId, memberId, memberType} |
{success} |
POST /api/circle/create |
创建圈子 |
📱小程序 |
{name, type, matchSource, sourceId, creatorId, creatorType} |
SocialCircle对象 |
健康圈子
| 端点 |
说明 |
端口 |
请求数据 |
响应数据 |
POST /api/health/circle/list |
获取健康圈子列表 |
📱小程序 |
{familyId} |
[HealthCircle对象] |
POST /api/health/circle/create |
创建健康圈子 |
📱小程序 |
{name, description, familyId} |
HealthCircle对象 |
POST /api/health/circle/join |
通过邀请码加入健康圈子 |
📱小程序 |
{inviteCode, familyId} |
{success} |
POST /api/health/circle/leave |
退出健康圈子 |
📱小程序 |
{circleId, familyId} |
{success} |
POST /api/health/circle/ranking |
健康圈子排行榜 |
📱小程序 |
{circleId} |
{rankings: [...]} |
POST /api/health/family/ranking |
家庭健康排行 |
📱小程序 |
{circleId} |
{rankings: [...]} |
挑战
| 端点 |
说明 |
端口 |
请求数据 |
响应数据 |
POST /api/health/circle/challenge/list |
圈子挑战列表 |
📱小程序 |
{circleId} |
[CircleChallenge对象] |
POST /api/health/circle/challenge/history |
圈子挑战历史 |
📱小程序 |
{circleId} |
[CircleChallenge对象] |
POST /api/health/challenge/list |
家庭挑战列表 |
📱小程序 |
{familyId} |
[FamilyChallenge对象] |
POST /api/health/challenge/history |
家庭挑战历史 |
📱小程序 |
{familyId} |
[FamilyChallenge对象] |
POST /api/health/challenge/progress |
更新挑战进度 |
📱小程序 |
{challengeId, childId, delta} |
{success} |
联系人
| 端点 |
说明 |
端口 |
请求数据 |
响应数据 |
POST /api/contact/list |
获取联系人列表 |
📱小程序 |
Header: Authorization |
[ContactDTO对象](按亲密度降序) |
POST /api/contact/create |
创建联系人 |
📱小程序 |
{name, phone, relationshipType, ...} |
ContactDTO对象 |
POST /api/contact/update |
更新联系人 |
📱小程序 |
{id, name, phone, tags, ...} |
ContactDTO对象 |
POST /api/contact/delete |
删除联系人 |
📱小程序 |
{id} |
{success} |
POST /api/contact/detail |
获取联系人详情 |
📱小程序 |
{id} |
ContactDTO对象(含生日倒计时等) |
POST /api/contact/import-phone |
从手机导入联系人 |
📱小程序 |
{name, phone, extra} |
ContactDTO对象 |
POST /api/contact/interaction |
记录互动 |
📱小程序 |
{id} |
ContactDTO对象 |
POST /api/contact/invite-to-family |
邀请联系人加入家庭 |
📱小程序 |
{contactId, relationshipType, generationLevel} |
{contactId, invitedStatus, relationshipType} |
数据实体关系
erDiagram
SocialCircle ||--o{ SocialCircleMember : "一个圈子多个成员"
SocialCircle ||--o{ CircleChallenge : "一个圈子多个挑战"
HealthCircle ||--o{ HealthCircleMember : "一个健康圈多个家庭"
Family ||--o{ HealthCircleMember : "一个家庭加入多个健康圈"
User ||--o{ Contact : "一个用户多个联系人"
SocialCircle {
Long id PK
string name
string type "topic/activity/hobby/ability/product/health/provider"
string matchSource
Long sourceId
int memberCount
}
SocialCircleMember {
Long id PK
Long circleId FK
Long memberId
string memberType "parent/child"
}
HealthCircle {
Long id PK
string name
string description
Long creatorFamilyId
string inviteCode
int memberLimit
string status "active/closed"
}
HealthCircleMember {
Long id PK
Long circleId FK
Long familyId FK
string role "member/admin"
string status "active/inactive"
}
CircleChallenge {
Long id PK
Long circleId FK
string challengeType "checkin/step/meditation"
string title
int durationDays
string period "weekly/monthly"
string status "active/completed/cancelled"
}
Contact {
Long id PK
Long userId FK
string name
string phone
string relationshipType "family/friend/partner/colleague/other"
int intimacyLevel
string contactSource "phone/manual"
Long familyMemberId "关联家庭成员ID"
string invitedStatus "none/invited/accepted/declined"
}
完整性分析
| # |
维度 |
评估 |
说明 |
| 1 |
流程完整性 |
✅ 完整 |
覆盖社交圈子CRUD、健康圈子管理、圈子挑战、家庭挑战、联系人管理5个阶段,路径完整 |
| 2 |
异常路径 |
⚠️ 部分覆盖 |
加入圈子时已加入则直接返回成功(幂等);联系人导入时重复手机号会返回错误;邀请联系人时已是家庭成员也会返回错误 |
| 3 |
端点覆盖 |
✅ 完整 |
24个端点全部映射到流程图中,与CircleController、HealthCircleController、CircleChallengeController、FamilyChallengeController、ContactController的@PostMapping一致 |
| 4 |
角色覆盖 |
✅ 完整 |
社交圈子面向孩子(child),健康圈子和联系人面向家长(parent),分工明确 |
| 5 |
数据实体 |
✅ 完整 |
social_circle、social_circle_member、health_circle、health_circle_member、circle_challenge、contacts共6张核心表均在图中映射 |
| 6 |
一致性 |
✅ 与代码一致 |
所有端点路径与实际Controller中的@PostMapping匹配,边缘输出数据与代码逻辑一致 |