2026-09-10-pearl-diagram-redesign-design.md 17 KB

珍珠图重新设计:社会连接盘点系统

日期: 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 表新增字段

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 表

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 表

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

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 扩展

新增方法:

/** 计算并更新资源的价值分 */
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 新增接口

// 获取连接类型列表(供前端类型选择器使用)
@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

@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 扩展为两层同心圆

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 珍珠半径动态计算(按价值分映射)

// 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

{
  "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(响应格式变更)

{
  "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

请求体:

{ "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 月