瀏覽代碼

docs: 珍珠图社会连接盘点系统设计文档

Sisyphus Agent 1 周之前
父節點
當前提交
36b7cffc41
共有 1 個文件被更改,包括 488 次插入0 次删除
  1. 488 0
      docs/superpowers/specs/2026-09-10-pearl-diagram-redesign-design.md

+ 488 - 0
docs/superpowers/specs/2026-09-10-pearl-diagram-redesign-design.md

@@ -0,0 +1,488 @@
+# 珍珠图重新设计:社会连接盘点系统
+
+**日期**: 2026-09-10  
+**状态**: 初稿  
+**关联**: `2026-07-12-dimension-features-energy-map.md` 中「圈子(珍珠图)概念」  
+
+---
+
+## 背景
+
+当前珍珠图是「资源清单」实现:从联系人(PERSON)、帮助记录(SKILL)、手工登记(INFO/PLACE)聚合出 4 组弧形分布的珍珠节点。  
+书稿定义:「把可调用的外部资源串成珍珠项链,盘点'我有什么'」。
+
+新需求:将珍珠图重构为**社会连接盘点工具**,明确用户有哪些可依赖的外部资源,并按类型分级、定期互动维护。
+
+---
+
+## 核心设计决策
+
+| 决策点 | 选择 |
+|--------|------|
+| 布局 | 保留现有 Canvas 圆形布局,扩展为**两层同心圆**(内圈必备 12 组 + 外圈理想 13 组) |
+| 分类方式 | 新建固定枚举 `ConnectionType`(25 类),不允许用户自定义 |
+| 分级逻辑 | 系统自动计算价值分 + 用户手动覆盖优先级 |
+| 珍珠大小 | 按优先级/价值分映射半径(高价值=大珍珠,低价值=小珍珠) |
+| 互动记录 | 新增 `pearl_interaction_log` 表;定时任务每日生成提醒 |
+| 兼容性 | 现有 PERSON/SKILL/INFO/PLACE 数据保留为「历史资源」,不迁移 |
+
+---
+
+## 一、连接类型枚举(ConnectionType)
+
+连接类型分两层语义:
+- **必备社会连接(ESSENTIAL,12 类)**:用户必须拥有的核心资源,内圈展示
+- **理想社会连接(IDEAL,13 类)**:在必备基础上的扩展资源,外圈展示
+
+> 理想社会连接 = 必备社会连接(12 类)+ 理想扩展(13 类)= 共 25 类。
+
+### 1.1 必备社会连接(12 类,内圈)
+
+| 类型 Code | 中文名 | 建议互动周期 |
+|-----------|--------|-------------|
+| MEDICAL | 医疗 | 季度(3 月) |
+| EDUCATION | 教育 | 学期(约 6 月) |
+| PUBLIC_SECURITY | 公安 | 年度(12 月) |
+| AUTO | 汽车相关 | 半年(6 月) |
+| REAL_ESTATE | 房产服务 | 年度(12 月) |
+| TICKETING | 票务 | 年度(12 月) |
+| HANDYMAN | 多能工人 | 半年(6 月) |
+| APPLIANCE | 家电 | 年度(12 月) |
+| CATERING | 餐饮 | 季度(3 月) |
+| FOOD | 食品 | 季度(3 月) |
+| LEGAL | 法律 | 年度(12 月) |
+| WEEKEND_EXPERT | 周末达人 | 月度(1 月) |
+
+### 1.2 理想社会连接扩展(13 类,外圈)
+
+| 类型 Code | 中文名 | 建议互动周期 |
+|-----------|--------|-------------|
+| GOVERNMENT | 政府综合 | 年度(12 月) |
+| TAX | 税务 | 年度(12 月) |
+| BUSINESS_ADMIN | 工商 | 年度(12 月) |
+| BANK | 银行 | 半年(6 月) |
+| MEDIA | 媒体 | 年度(12 月) |
+| TRAVEL | 旅游 | 年度(12 月) |
+| LEADING_ENTERPRISE | 领军企业 | 年度(12 月) |
+| INDUSTRY_BENCHMARK | 行业标杆 | 年度(12 月) |
+| OVERSEAS | 国外 | 年度(12 月) |
+| UNIVERSITY | 高校 | 年度(12 月) |
+| FINANCE | 金融 | 年度(12 月) |
+| SENIOR_LOCAL | 资深土著 | 半年(6 月) |
+| KEY_CITY | 北上广等关键城市 | 年度(12 月) |
+
+> **说明**:建议互动周期为产品默认值,后续可在管理端调整。前端通过 API 获取枚举(便于未来调整顺序/周期/文案)。
+
+---
+
+## 二、数据库变更
+
+### 2.1 resource_items 表新增字段
+
+```sql
+ALTER TABLE resource_items
+    ADD COLUMN connection_type VARCHAR(50) NOT NULL DEFAULT '' COMMENT '关联 ConnectionType 枚举名',
+    ADD COLUMN priority TINYINT DEFAULT 2 COMMENT '优先级:1=高 2=中 3=低(手动覆盖用)',
+    ADD COLUMN value_score INT DEFAULT 0 COMMENT '价值分 0-100(自动计算,用户可手动覆盖)',
+    ADD COLUMN last_interaction_at DATETIME DEFAULT NULL COMMENT '最近互动时间',
+    ADD COLUMN interaction_count INT DEFAULT 0 COMMENT '互动总次数',
+    ADD INDEX idx_ri_connection_type (connection_type);
+```
+
+**迁移逻辑**(DatabaseInitializer 新增迁移):
+- 现有 INFO/PLACE/SKILL 类型资源:
+  - `connection_type = ''`(空,标记为历史资源,不参与 25 类分组)
+  - `priority = 2`(默认中)
+  - `value_score = 50`(默认中)
+  - `last_interaction_at = null`
+  - `interaction_count = 0`
+- 原有 `type` 字段保留不变(INFO/PLACE/SKILL 作为兼容字段)
+
+### 2.2 新增 pearl_interaction_log 表
+
+```sql
+CREATE TABLE IF NOT EXISTS pearl_interaction_log (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    user_id BIGINT NOT NULL COMMENT '操作人',
+    resource_item_id BIGINT NOT NULL COMMENT '关联资源',
+    interaction_type VARCHAR(20) NOT NULL COMMENT 'PHONE/WECHAT/MEETING/OTHER',
+    content VARCHAR(500) DEFAULT NULL COMMENT '互动内容简记',
+    happened_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '互动发生时间',
+    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    INDEX idx_pil_user (user_id),
+    INDEX idx_pil_resource (resource_item_id),
+    INDEX idx_pil_happened (happened_at)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='珍珠图互动日志';
+```
+
+### 2.3 新增 pearl_interaction_reminder 表
+
+```sql
+CREATE TABLE IF NOT EXISTS pearl_interaction_reminder (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    user_id BIGINT NOT NULL,
+    resource_item_id BIGINT NOT NULL,
+    connection_type VARCHAR(50) NOT NULL,
+    suggest_interval_month INT NOT NULL COMMENT '建议互动周期(月)',
+    last_interaction_at DATETIME DEFAULT NULL,
+    days_since_last INT NOT NULL COMMENT '距上次互动天数',
+    status VARCHAR(20) DEFAULT 'PENDING' COMMENT 'PENDING/DONE/DISMISSED',
+    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    INDEX idx_pir_user_status (user_id, status),
+    INDEX idx_pir_resource (resource_item_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='珍珠图互动提醒';
+```
+
+---
+
+## 三、后端设计
+
+### 3.1 新增枚举类 ConnectionType.java
+
+```java
+public enum ConnectionType {
+    // 必备社会连接(ESSENTIAL)— 内圈,12 类
+    MEDICAL("医疗", "ESSENTIAL", 3),
+    EDUCATION("教育", "ESSENTIAL", 6),
+    PUBLIC_SECURITY("公安", "ESSENTIAL", 12),
+    AUTO("汽车相关", "ESSENTIAL", 6),
+    REAL_ESTATE("房产服务", "ESSENTIAL", 12),
+    TICKETING("票务", "ESSENTIAL", 12),
+    HANDYMAN("多能工人", "ESSENTIAL", 6),
+    APPLIANCE("家电", "ESSENTIAL", 12),
+    CATERING("餐饮", "ESSENTIAL", 3),
+    FOOD("食品", "ESSENTIAL", 3),
+    LEGAL("法律", "ESSENTIAL", 12),
+    WEEKEND_EXPERT("周末达人", "ESSENTIAL", 1),
+
+    // 理想社会连接扩展(IDEAL)— 外圈,13 类
+    GOVERNMENT("政府综合", "IDEAL", 12),
+    TAX("税务", "IDEAL", 12),
+    BUSINESS_ADMIN("工商", "IDEAL", 12),
+    BANK("银行", "IDEAL", 6),
+    MEDIA("媒体", "IDEAL", 12),
+    TRAVEL("旅游", "IDEAL", 12),
+    LEADING_ENTERPRISE("领军企业", "IDEAL", 12),
+    INDUSTRY_BENCHMARK("行业标杆", "IDEAL", 12),
+    OVERSEAS("国外", "IDEAL", 12),
+    UNIVERSITY("高校", "IDEAL", 12),
+    FINANCE("金融", "IDEAL", 12),
+    SENIOR_LOCAL("资深土著", "IDEAL", 6),
+    KEY_CITY("北上广等关键城市", "IDEAL", 12);
+
+    private final String label;
+    private final String category; // ESSENTIAL / IDEAL
+    private final int suggestIntervalMonth;
+
+    ConnectionType(String label, String category, int suggestIntervalMonth) {
+        this.label = label;
+        this.category = category;
+        this.suggestIntervalMonth = suggestIntervalMonth;
+    }
+    // getters...
+}
+```
+
+### 3.2 ResourceService 扩展
+
+新增方法:
+```java
+/** 计算并更新资源的价值分 */
+public void recalculateValueScore(Long userId, Long itemId)
+
+/** 自动计算价值分(纯函数,不写 DB) */
+public int calculateValueScore(ResourceItem item, List<InteractionLog> logs)
+    // 类型基础权重:ESSENTIAL=30, IDEAL=20
+    // 近90天互动次数 × 5,上限 30
+    // 最近互动时效性:≤30天=+20, ≤90天=+10, ≤180天=+5
+    // 互动总量 × 2,上限 20
+    // 总分为 0-100
+```
+
+### 3.3 PearlController 新增接口
+
+```java
+// 获取连接类型列表(供前端类型选择器使用)
+@PostMapping("/connection-types")
+public Result<List<Map<String, Object>>> getConnectionTypes()
+
+// 记录互动
+@PostMapping("/interaction/add")
+public Result<Void> addInteraction(@RequestBody Map params, @RequestAttribute Long userId)
+// params: itemId, interactionType, content
+
+// 获取互动历史
+@PostMapping("/interaction/list")
+public Result<List<Map<String, Object>>> getInteractionList(
+    @RequestBody Map params, @RequestAttribute Long userId)
+// params: itemId, page, size
+
+// 获取待办提醒列表
+@PostMapping("/reminder/list")
+public Result<List<Map<String, Object>>> getReminders(@RequestAttribute Long userId)
+
+// 更新资源优先级(手动覆盖)
+@PostMapping("/item/update-priority")
+public Result<Void> updatePriority(@RequestBody Map params, @RequestAttribute Long userId)
+// params: itemId, priority (1/2/3)
+```
+
+### 3.4 定时任务 PearlReminderScheduler
+
+```java
+@Scheduled(cron = "0 0 8 * * ?") // 每日 08:00
+public void generateReminders() {
+    // 遍历所有用户的 25 类资源(connection_type 非空)
+    // 对每个资源:
+    //   daysSinceLast = today - lastInteractionAt
+    //   若 daysSinceLast >= suggestIntervalMonth * 30
+    //     且不存在 PENDING 提醒 → 创建提醒记录
+    //   若 status = DONE/DISMISSED → 跳过
+}
+```
+
+---
+
+## 四、前端设计
+
+### 4.1 PearlDiagram.vue 核心变更
+
+#### 4.1.1 groupConfigs 扩展为两层同心圆
+
+```javascript
+groupConfigs: [
+  // 内圈(必备 12 组)
+  { type: 'MEDICAL', typeName: '医疗', color: '#EF4444', radiusPct: 0.28, startAngle: -Math.PI * 0.85, endAngle: -Math.PI * 0.15, ring: 'inner' },
+  { type: 'EDUCATION', typeName: '教育', color: '#3B82F6', radiusPct: 0.28, startAngle: -Math.PI * 0.85, endAngle: -Math.PI * 0.15, ring: 'inner' },
+  // ... 其余 10 个内圈类型(每组弧度均分,避免重叠)
+  // 外圈(理想 13 组)
+  { type: 'GOVERNMENT', typeName: '政府综合', color: '#8B5CF6', radiusPct: 0.55, startAngle: -Math.PI * 0.7, endAngle: Math.PI * 0.2, ring: 'outer' },
+  // ... 其余 12 个外圈类型
+]
+```
+
+**布局说明**:
+- 内圈半径比例 `radiusPct = 0.28`,外圈 `radiusPct = 0.55`
+- 每组分配一个角度区间,组内珍珠沿弧线等间距分布
+- 25 组平均分配圆周:内圈 12 组 × 约 26° 弧 + 间隙,外圈 13 组 × 约 24° 弧 + 间隙
+- 由于内圈/外圈半径不同、颜色不同,即使角度重叠也能区分
+
+#### 4.1.2 珍珠半径动态计算(按价值分映射)
+
+```javascript
+// buildLayout 中计算每个珍珠的 radius
+var valueScore = item.valueScore || 0
+var priority = item.priority || 2   // 手动优先级优先于自动
+var priorityMultiplier = priority === 1 ? 1.4 : priority === 3 ? 0.7 : 1.0
+var itemRadius = minDim * config.radiusPct * 0.09 * priorityMultiplier
+// 内圈珍珠半径范围约 8-20px,外圈 8-20px,最小 8,最大 26
+itemRadius = Math.max(8, Math.min(26, itemRadius))
+```
+
+#### 4.1.3 视觉规范
+
+| 元素 | 样式 |
+|------|------|
+| 中心节点「我」 | 半径 36px,实心圆,深橙色 #F97316 |
+| 内圈连线 | 从中心放射至每组弧心,透明度 30% |
+| 外圈连线 | 同上,透明度 20% |
+| 资源珍珠 | 实心圆,颜色 = 类型颜色,半径 = 优先级映射 |
+| 高价值珍珠(优先级 1) | 加粗边框(2px 白色描边) |
+| 分组标签 | 置于弧外侧,字号 20rpx,颜色 = 类型颜色 |
+| 互动逾期珍珠 | 边缘显示红色角标「逾期N天」 |
+
+### 4.2 pearl-add-resource.vue 扩展
+
+**现有流程**:选类型(INFO/PLACE/SKILL)→ 填名称/描述 → 关联联系人 → 提交
+
+**新流程**:
+```
+1. 底部弹出选择器:选择连接类型(25 类,分「必备」/「理想」两个分组 Tab)
+2. 进入现有表单:名称、描述、关联联系人
+3. 提交(connection_type 必填)
+```
+
+### 4.3 珍珠弹窗扩展
+
+点击珍珠后弹窗新增:
+- **互动记录**折叠面板(最近 5 条,显示时间/方式/内容)
+- **联系按钮**:底部 ActionSheet 选方式 → 填简记 → 确认 → 调 `/interaction/add`
+- **优先级调整**:三档选择(高/中/低)→ 调 `/item/update-priority`
+
+### 4.4 提醒入口
+
+在珍珠图页面顶部新增「提醒」Tab:
+- 红点计数(PENDING 提醒数)
+- 点击进入提醒列表
+- 每条提醒:资源名称、连接类型、距上次互动天数、操作「去联系」「稍后提醒」
+
+---
+
+## 五、API 响应格式
+
+### 5.1 POST /api/pearl/connection-types
+
+```json
+{
+  "code": 200,
+  "data": [
+    { "code": "MEDICAL", "label": "医疗", "category": "ESSENTIAL", "suggestIntervalMonth": 3 },
+    { "code": "EDUCATION", "label": "教育", "category": "ESSENTIAL", "suggestIntervalMonth": 6 },
+    { "code": "GOVERNMENT", "label": "政府综合", "category": "IDEAL", "suggestIntervalMonth": 12 }
+    // ... 共 25 项
+  ]
+}
+```
+
+### 5.2 POST /api/pearl/resources(响应格式变更)
+
+```json
+{
+  "code": 200,
+  "data": {
+    "groups": [
+      {
+        "type": "MEDICAL",
+        "typeName": "医疗",
+        "category": "ESSENTIAL",
+        "color": "#EF4444",
+        "ring": "inner",
+        "items": [
+          {
+            "id": 1,
+            "name": "社区王医生",
+            "description": "儿科,社区医院主治医",
+            "avatar": null,
+            "valueScore": 72,
+            "priority": 1,
+            "contactId": 5,
+            "lastInteractionAt": "2026-08-15T10:30:00",
+            "interactionCount": 8,
+            "daysSinceLast": 26
+          }
+        ]
+      }
+      // ... 共 25 组(为空时 items=[])
+    ],
+    "legacyGroups": [
+      // 原有 PERSON/SKILL/INFO/PLACE,作为历史资源(connection_type='' 的资源)
+    ]
+  }
+}
+```
+
+### 5.3 POST /api/pearl/interaction/add
+
+请求体:
+```json
+{ "itemId": 1, "interactionType": "WECHAT", "content": "咨询孩子过敏问题" }
+```
+成功:`{ "code": 200 }`
+
+### 5.4 POST /api/pearl/reminder/list
+
+返回当前用户所有 PENDING 状态的提醒。
+
+---
+
+## 六、交互流程图
+
+```
+打开珍珠图页
+    ↓
+调用 /api/pearl/resources
+    ↓
+渲染两层同心圆(内圈必备 12 组 / 外圈理想 13 组)
+    ↓
+点击珍珠
+    ↓
+弹窗:名称 / 类型 / 优先级 / 互动记录 / 按钮[联系][编辑][删除]
+    ↓
+点击「联系」
+    ↓
+底部弹出 ActionSheet(电话/微信/见面/其他)
+    ↓
+填写互动内容 → 提交 /api/pearl/interaction/add
+    ↓
+更新珍珠 radius(实时重绘)+ 刷新互动记录
+    ↓
+(定时任务)每日 08:00 检查互动频率 → 生成提醒
+    ↓
+珍珠边缘显示「逾期N天」角标 → 点击跳转提醒列表
+```
+
+---
+
+## 七、迁移计划
+
+### Migration 步骤
+
+1. **DatabaseInitializer 新增迁移**:
+   - `migration_XXX`: 给 `resource_items` 添加新字段,存量数据填充默认值
+   - `migration_XXX+1`: 创建 `pearl_interaction_log` 表
+   - `migration_XXX+2`: 创建 `pearl_interaction_reminder` 表
+
+2. **后端**:
+   - 新增 `ConnectionType.java` 枚举(25 类)
+   - 扩展 `ResourceService.java`(新增价值分计算、互动、提醒方法)
+   - 扩展 `PearlController.java`(新增 5 个接口)
+   - 新增 `PearlReminderScheduler.java`(定时任务)
+   - 新增 `PearlInteractionLog.java`、`PearlInteractionReminder.java` 实体 + Mapper
+
+3. **前端**:
+   - 扩展 `PearlDiagram.vue`(同心圆布局算法 + 半径计算)
+   - 扩展 `pearl-add-resource.vue`(25 类类型选择器)
+   - 扩展弹窗交互(联系按钮 + 互动记录面板)
+   - 新增提醒列表页
+   - 更新 `api.js`(新增 5 个 API 方法)
+
+4. **测试验证**:
+   - `mvn clean compile` 无编译错误
+   - 小程序端:25 组分类渲染正常、点击交互正常
+   - 互动记录写入/读取正常
+   - 定时任务生成提醒正常
+
+---
+
+## 八、非功能需求
+
+| 项目 | 要求 |
+|------|------|
+| **性能** | Canvas 单帧 < 16ms(25 组 × 平均 3-5 珍珠 ≈ 100 节点) |
+| **兼容性** | iOS/Android 微信基础库 2.25.0+ |
+| **空状态** | 无任何新类型资源时显示引导按钮「登记你的第一个社会连接」 |
+| **异常处理** | 连接类型不在枚举 → 拦截报错;互动日志写入失败 → 回滚 + 提示 |
+| **权限** | 复用现有 JWT 认证,仅本人可见 |
+
+---
+
+## 附录:25 类 ConnectionType 完整列表
+
+| # | Code | 中文名 | Category | 建议周期 |
+|---|------|--------|----------|---------|
+| 1 | MEDICAL | 医疗 | ESSENTIAL | 3 月 |
+| 2 | EDUCATION | 教育 | ESSENTIAL | 6 月 |
+| 3 | PUBLIC_SECURITY | 公安 | ESSENTIAL | 12 月 |
+| 4 | AUTO | 汽车相关 | ESSENTIAL | 6 月 |
+| 5 | REAL_ESTATE | 房产服务 | ESSENTIAL | 12 月 |
+| 6 | TICKETING | 票务 | ESSENTIAL | 12 月 |
+| 7 | HANDYMAN | 多能工人 | ESSENTIAL | 6 月 |
+| 8 | APPLIANCE | 家电 | ESSENTIAL | 12 月 |
+| 9 | CATERING | 餐饮 | ESSENTIAL | 3 月 |
+| 10 | FOOD | 食品 | ESSENTIAL | 3 月 |
+| 11 | LEGAL | 法律 | ESSENTIAL | 12 月 |
+| 12 | WEEKEND_EXPERT | 周末达人 | ESSENTIAL | 1 月 |
+| 13 | GOVERNMENT | 政府综合 | IDEAL | 12 月 |
+| 14 | TAX | 税务 | IDEAL | 12 月 |
+| 15 | BUSINESS_ADMIN | 工商 | IDEAL | 12 月 |
+| 16 | BANK | 银行 | IDEAL | 6 月 |
+| 17 | MEDIA | 媒体 | IDEAL | 12 月 |
+| 18 | TRAVEL | 旅游 | IDEAL | 12 月 |
+| 19 | LEADING_ENTERPRISE | 领军企业 | IDEAL | 12 月 |
+| 20 | INDUSTRY_BENCHMARK | 行业标杆 | IDEAL | 12 月 |
+| 21 | OVERSEAS | 国外 | IDEAL | 12 月 |
+| 22 | UNIVERSITY | 高校 | IDEAL | 12 月 |
+| 23 | FINANCE | 金融 | IDEAL | 12 月 |
+| 24 | SENIOR_LOCAL | 资深土著 | IDEAL | 6 月 |
+| 25 | KEY_CITY | 北上广等关键城市 | IDEAL | 12 月 |