CI/CD Pipeline / test-admin (push) Waiting to run
CI/CD Pipeline / test-bigscreen (push) Waiting to run
CI/CD Pipeline / build-push (ljwx-admin) (push) Blocked by required conditions
CI/CD Pipeline / build-push (ljwx-bigscreen) (push) Blocked by required conditions
CI/CD Pipeline / build-push (ljwx-boot) (push) Blocked by required conditions
CI/CD Pipeline / update-deploy (push) Blocked by required conditions
CI/CD Pipeline / build-pr (ljwx-admin) (push) Blocked by required conditions
CI/CD Pipeline / build-pr (ljwx-bigscreen) (push) Blocked by required conditions
CI/CD Pipeline / build-pr (ljwx-boot) (push) Blocked by required conditions
CI/CD Pipeline / security-scan (push) Has been cancelled
CI/CD Pipeline / test-build-boot (push) Has been cancelled
新增核心功能: - 健康画像生成系统(用户/部门/组织基线) - 风险评估框架(心血管/运动/呼吸/睡眠) - 行为画像分析(饮食/运动/睡眠/健康关注度) - 数据质量评分和告警 数据库迁移: - V1.3.0~V1.7.0 健康监测表结构 前端增强: - ljwx-admin: BigScreen集成、健康搜索优化 - ljwx-bigscreen: SSO认证、登录界面 文档体系: - 强制文档管理规范(kebab-case、分类、Git hooks) - 架构文档、开发指南、运维手册 - 工程蓝图 v2.1 CI/CD: - 文档验证工作流 - 生产就绪性检查脚本 - 完整测试覆盖 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
35 KiB
35 KiB
Phase 2 Sprint 8 - 行为画像系统架构设计
文档信息
| 项目 | 内容 |
|---|---|
| 文档标题 | 行为画像系统架构设计 |
| 版本 | v1.0 |
| 创建日期 | 2026-01-20 |
| 作者 | Backend Dev 1 (Claude Code Sonnet 4.5) |
| 状态 | ✅ 设计评审通过 |
| 关联任务 | T2.2.1 - 行为画像架构设计 |
📋 目录
系统概述
业务目标
行为画像系统旨在通过分析用户的健康相关行为数据,识别用户的行为模式和习惯特征,为个性化健康干预提供依据。
核心价值
- 行为模式识别: 自动识别用户的运动、睡眠、饮食、健康关注等行为模式
- 个性化洞察: 基于行为数据生成个性化的健康建议
- 趋势预测: 识别行为趋势变化,提前预警不健康行为
- 干预基础: 为 AI 健康顾问提供行为画像上下文
设计原则
- 可扩展性: 支持新增行为维度,不修改核心架构
- 模块化: 每个行为分析器独立实现,便于维护
- 数据驱动: 基于实际数据统计,避免主观假设
- 隐私保护: 行为画像仅用于个人健康管理,不泄露给第三方
四类行为维度设计
1. 运动习惯分析 (Exercise Habits)
分析指标
| 指标名称 | 数据来源 | 计算周期 | 用途 |
|---|---|---|---|
| 步数统计 | t_user_health_profile.step_count | 7天 | 识别运动活跃度 |
| 运动频率 | 有效运动天数 / 7天 | 7天 | 评估运动习惯稳定性 |
| 时段偏好 | t_step_data.upload_time | 30天 | 识别最佳运动时间 |
| 运动强度 | t_user_health_profile.calorie_total | 7天 | 评估运动消耗水平 |
| 运动距离 | t_user_health_profile.distance | 7天 | 辅助活跃度评估 |
画像输出
public class ExerciseHabits {
private String activityLevel; // 运动积极性: SEDENTARY/LIGHTLY_ACTIVE/MODERATELY_ACTIVE/VERY_ACTIVE
private Double avgDailySteps; // 日均步数
private Integer activeWeekDays; // 7天内有效运动天数
private String preferredTimeSlot; // 最佳运动时段: MORNING/AFTERNOON/EVENING
private Double consistency; // 习惯稳定性评分 (0-100)
private String trend; // 趋势: IMPROVING/STABLE/DECLINING
}
分类规则
| 积极性等级 | 日均步数范围 | 有效运动天数 | 描述 |
|---|---|---|---|
| VERY_ACTIVE | ≥ 10,000 | ≥ 5天 | 非常活跃,运动习惯优秀 |
| MODERATELY_ACTIVE | 7,000 - 9,999 | ≥ 4天 | 中等活跃,运动习惯良好 |
| LIGHTLY_ACTIVE | 4,000 - 6,999 | ≥ 3天 | 轻度活跃,需提升运动量 |
| SEDENTARY | < 4,000 | < 3天 | 久坐为主,急需改善 |
2. 睡眠习惯分析 (Sleep Habits)
分析指标
| 指标名称 | 数据来源 | 计算周期 | 用途 |
|---|---|---|---|
| 入睡时间 | t_sleep_data.sleep_start | 7天 | 识别睡眠类型 |
| 睡眠时长 | t_user_health_profile.sleep_duration | 7天 | 评估睡眠充足度 |
| 睡眠质量 | t_user_health_profile.deep_sleep_ratio | 7天 | 评估睡眠效率 |
| 中断次数 | t_user_health_profile.sleep_interruptions | 7天 | 评估睡眠连续性 |
| 起床时间 | t_sleep_data.sleep_end | 7天 | 辅助睡眠类型识别 |
画像输出
public class SleepHabits {
private String sleepType; // 睡眠类型: EARLY_BIRD/NIGHT_OWL/NORMAL
private Double avgSleepDuration; // 平均睡眠时长 (分钟)
private String qualityRating; // 质量评级: EXCELLENT/GOOD/FAIR/POOR
private LocalTime avgBedTime; // 平均入睡时间
private LocalTime avgWakeTime; // 平均起床时间
private Double consistency; // 睡眠规律性评分 (0-100)
private String trend; // 趋势: IMPROVING/STABLE/DECLINING
}
分类规则
睡眠类型识别:
| 类型 | 入睡时间范围 | 起床时间范围 | 描述 |
|---|---|---|---|
| EARLY_BIRD (早睡型) | 21:00 - 23:00 | 05:00 - 07:00 | 早睡早起,生物钟健康 |
| NIGHT_OWL (夜猫子) | 00:00 - 02:00 | 08:00 - 10:00 | 晚睡晚起,需调整作息 |
| NORMAL (正常型) | 23:00 - 00:00 | 07:00 - 08:00 | 标准作息,符合生理规律 |
质量评级标准:
| 评级 | 平均时长 | 深睡比例 | 中断次数 | 描述 |
|---|---|---|---|---|
| EXCELLENT | ≥ 420分钟 (7h) | ≥ 25% | ≤ 1次 | 睡眠优秀,无需调整 |
| GOOD | 360-419分钟 | 20-24% | ≤ 2次 | 睡眠良好,维持现状 |
| FAIR | 300-359分钟 | 15-19% | ≤ 3次 | 睡眠一般,建议改善 |
| POOR | < 300分钟 (5h) | < 15% | > 3次 | 睡眠不佳,急需干预 |
3. 饮食规律分析 (Diet Patterns)
分析指标
| 指标名称 | 数据来源 | 计算周期 | 用途 |
|---|---|---|---|
| 用餐时间 | t_meal_data.meal_time | 7天 | 识别饮食规律性 |
| 热量摄入 | t_meal_data.calories | 7天 | 评估饮食合理性 |
| 三餐完整度 | 早/中/晚餐记录数 | 7天 | 评估饮食习惯 |
| 用餐间隔 | 相邻用餐时间差 | 7天 | 识别饮食节奏 |
画像输出
public class DietPatterns {
private String regularityLevel; // 规律性等级: HIGHLY_REGULAR/REGULAR/IRREGULAR/CHAOTIC
private Double regularityScore; // 规律性评分 (0-100)
private Integer avgMealsPerDay; // 日均用餐次数
private Boolean breakfastHabit; // 是否有早餐习惯
private Map<String, LocalTime> mealTimes; // 各餐平均时间: {breakfast: 07:30, lunch: 12:00, dinner: 18:30}
private String trend; // 趋势: IMPROVING/STABLE/DECLINING
}
分类规则
| 规律性等级 | 三餐完整率 | 时间波动 (分钟) | 描述 |
|---|---|---|---|
| HIGHLY_REGULAR | ≥ 90% | ≤ 30 | 饮食规律优秀,三餐定时定量 |
| REGULAR | 70-89% | ≤ 60 | 饮食规律良好,基本固定时间 |
| IRREGULAR | 50-69% | ≤ 120 | 饮食不规律,需改善作息 |
| CHAOTIC | < 50% | > 120 | 饮食混乱,严重影响健康 |
注: 当前版本由于缺少 t_meal_data 表,饮食规律分析将暂时返回 "DATA_UNAVAILABLE" 状态,等待后续数据源接入。
4. 健康关注度分析 (Health Attention)
分析指标
| 指标名称 | 数据来源 | 计算周期 | 用途 |
|---|---|---|---|
| 数据上传频率 | t_user_health_data.upload_time | 30天 | 评估数据同步习惯 |
| 设备佩戴率 | 有数据天数 / 30天 | 30天 | 评估设备使用习惯 |
| 画像查看次数 | t_user_profile_view_log | 30天 | 评估健康关注程度 |
| 健康建议阅读率 | 阅读数 / 推送数 | 30天 | 评估健康意识 |
画像输出
public class HealthAttention {
private String attentionLevel; // 关注度等级: HIGHLY_ENGAGED/ENGAGED/PASSIVE/INACTIVE
private Double deviceWearRate; // 设备佩戴率 (%)
private Integer avgDailyUploads; // 日均数据上传次数
private Integer profileViewsPerMonth; // 月画像查看次数
private Double engagementScore; // 健康参与度评分 (0-100)
private String trend; // 趋势: IMPROVING/STABLE/DECLINING
}
分类规则
| 关注度等级 | 设备佩戴率 | 数据上传频率 | 画像查看次数 | 描述 |
|---|---|---|---|---|
| HIGHLY_ENGAGED | ≥ 90% | 每天 ≥ 3次 | ≥ 10次/月 | 高度关注健康,数据完整 |
| ENGAGED | 70-89% | 每天 1-2次 | 5-9次/月 | 关注健康,习惯良好 |
| PASSIVE | 50-69% | 每2-3天1次 | 1-4次/月 | 较少关注,需激励 |
| INACTIVE | < 50% | 每周 < 2次 | 0次/月 | 不关注健康,急需激活 |
核心算法设计
1. 运动习惯分析算法
算法输入
List<HealthProfile> last7DaysProfiles // 近7天健康画像
算法流程
public ExerciseHabits analyzeExerciseHabits(List<HealthProfile> profiles) {
// 1. 计算统计指标
double avgDailySteps = profiles.stream()
.mapToInt(HealthProfile::getStepCount)
.average().orElse(0.0);
int activeWeekDays = (int) profiles.stream()
.filter(p -> p.getStepCount() != null && p.getStepCount() >= 3000)
.count();
double avgCalories = profiles.stream()
.mapToDouble(p -> p.getCalorieTotal() != null ? p.getCalorieTotal().doubleValue() : 0.0)
.average().orElse(0.0);
// 2. 确定活跃度等级
String activityLevel = determineActivityLevel(avgDailySteps, activeWeekDays);
// 3. 计算稳定性评分 (标准差越小,稳定性越高)
double stdDev = calculateStandardDeviation(
profiles.stream().mapToInt(HealthProfile::getStepCount).toArray()
);
double consistency = Math.max(0, 100 - (stdDev / avgDailySteps * 100));
// 4. 识别最佳运动时段 (需结合 t_step_data 分时数据)
String preferredTimeSlot = identifyPreferredTimeSlot(profiles);
// 5. 计算趋势 (线性回归斜率)
String trend = calculateTrend(profiles, HealthProfile::getStepCount);
return ExerciseHabits.builder()
.activityLevel(activityLevel)
.avgDailySteps(avgDailySteps)
.activeWeekDays(activeWeekDays)
.preferredTimeSlot(preferredTimeSlot)
.consistency(consistency)
.trend(trend)
.build();
}
private String determineActivityLevel(double avgSteps, int activeDays) {
if (avgSteps >= 10000 && activeDays >= 5) return "VERY_ACTIVE";
if (avgSteps >= 7000 && activeDays >= 4) return "MODERATELY_ACTIVE";
if (avgSteps >= 4000 && activeDays >= 3) return "LIGHTLY_ACTIVE";
return "SEDENTARY";
}
2. 睡眠习惯分析算法
算法流程
public SleepHabits analyzeSleepHabits(List<HealthProfile> profiles, List<SleepData> sleepData) {
// 1. 计算平均睡眠时长
double avgDuration = profiles.stream()
.filter(p -> p.getSleepDuration() != null)
.mapToInt(HealthProfile::getSleepDuration)
.average().orElse(0.0);
// 2. 计算平均入睡时间
LocalTime avgBedTime = calculateAverageBedTime(sleepData);
LocalTime avgWakeTime = calculateAverageWakeTime(sleepData);
// 3. 识别睡眠类型
String sleepType = determineSleepType(avgBedTime, avgWakeTime);
// 4. 评估睡眠质量
double avgDeepSleepRatio = profiles.stream()
.filter(p -> p.getDeepSleepRatio() != null)
.mapToDouble(p -> p.getDeepSleepRatio().doubleValue())
.average().orElse(0.0);
double avgInterruptions = profiles.stream()
.filter(p -> p.getSleepInterruptions() != null)
.mapToInt(HealthProfile::getSleepInterruptions)
.average().orElse(0.0);
String qualityRating = determineSleepQuality(avgDuration, avgDeepSleepRatio, avgInterruptions);
// 5. 计算规律性 (入睡时间标准差)
double consistency = calculateSleepConsistency(sleepData);
// 6. 计算趋势
String trend = calculateTrend(profiles, HealthProfile::getSleepDuration);
return SleepHabits.builder()
.sleepType(sleepType)
.avgSleepDuration(avgDuration)
.qualityRating(qualityRating)
.avgBedTime(avgBedTime)
.avgWakeTime(avgWakeTime)
.consistency(consistency)
.trend(trend)
.build();
}
private String determineSleepType(LocalTime bedTime, LocalTime wakeTime) {
int bedHour = bedTime.getHour();
int wakeHour = wakeTime.getHour();
if (bedHour >= 21 && bedHour < 23 && wakeHour >= 5 && wakeHour < 7) {
return "EARLY_BIRD";
} else if ((bedHour >= 0 && bedHour < 2) && wakeHour >= 8 && wakeHour < 10) {
return "NIGHT_OWL";
} else {
return "NORMAL";
}
}
private String determineSleepQuality(double duration, double deepRatio, double interruptions) {
if (duration >= 420 && deepRatio >= 0.25 && interruptions <= 1) return "EXCELLENT";
if (duration >= 360 && deepRatio >= 0.20 && interruptions <= 2) return "GOOD";
if (duration >= 300 && deepRatio >= 0.15 && interruptions <= 3) return "FAIR";
return "POOR";
}
3. 饮食规律分析算法
算法流程 (当前版本)
public DietPatterns analyzeDietPatterns(Long userId) {
// 注: 当前版本缺少 t_meal_data 表,返回占位符结果
return DietPatterns.builder()
.regularityLevel("DATA_UNAVAILABLE")
.regularityScore(0.0)
.avgMealsPerDay(0)
.breakfastHabit(false)
.mealTimes(Collections.emptyMap())
.trend("UNKNOWN")
.remark("饮食数据表暂未实现,待后续版本接入")
.build();
}
算法流程 (未来版本)
public DietPatterns analyzeDietPatterns(List<MealData> mealData) {
// 1. 统计三餐完整度
int breakfastCount = countMealsByType(mealData, "BREAKFAST");
int lunchCount = countMealsByType(mealData, "LUNCH");
int dinnerCount = countMealsByType(mealData, "DINNER");
double completeness = (breakfastCount + lunchCount + dinnerCount) / (7.0 * 3) * 100;
// 2. 计算各餐平均时间
Map<String, LocalTime> avgMealTimes = calculateAverageMealTimes(mealData);
// 3. 计算时间波动 (标准差)
double timeVariation = calculateMealTimeVariation(mealData);
// 4. 确定规律性等级
String regularityLevel = determineDietRegularity(completeness, timeVariation);
// 5. 计算规律性评分
double score = calculateRegularityScore(completeness, timeVariation);
return DietPatterns.builder()
.regularityLevel(regularityLevel)
.regularityScore(score)
.avgMealsPerDay((breakfastCount + lunchCount + dinnerCount) / 7)
.breakfastHabit(breakfastCount >= 5)
.mealTimes(avgMealTimes)
.trend("STABLE")
.build();
}
4. 健康关注度分析算法
算法流程
public HealthAttention analyzeHealthAttention(Long userId) {
LocalDate endDate = LocalDate.now();
LocalDate startDate = endDate.minusDays(30);
// 1. 计算设备佩戴率 (有数据的天数 / 30天)
int daysWithData = healthProfileMapper.countDaysWithData(userId, startDate, endDate);
double wearRate = (daysWithData / 30.0) * 100;
// 2. 计算日均上传次数
int totalUploads = healthDataMapper.countUploads(userId, startDate, endDate);
int avgDailyUploads = totalUploads / 30;
// 3. 统计画像查看次数 (需新建 t_user_profile_view_log 表)
int profileViews = profileViewLogMapper.countViews(userId, startDate, endDate);
// 4. 确定关注度等级
String attentionLevel = determineAttentionLevel(wearRate, avgDailyUploads, profileViews);
// 5. 计算参与度评分
double engagementScore = calculateEngagementScore(wearRate, avgDailyUploads, profileViews);
// 6. 计算趋势 (对比前30天)
String trend = calculateAttentionTrend(userId, startDate);
return HealthAttention.builder()
.attentionLevel(attentionLevel)
.deviceWearRate(wearRate)
.avgDailyUploads(avgDailyUploads)
.profileViewsPerMonth(profileViews)
.engagementScore(engagementScore)
.trend(trend)
.build();
}
private String determineAttentionLevel(double wearRate, int uploads, int views) {
if (wearRate >= 90 && uploads >= 3 && views >= 10) return "HIGHLY_ENGAGED";
if (wearRate >= 70 && uploads >= 1 && views >= 5) return "ENGAGED";
if (wearRate >= 50 && views >= 1) return "PASSIVE";
return "INACTIVE";
}
数据模型设计
DTO 类设计
BehavioralProfileDTO.java
package com.ljwx.modules.health.domain.dto.behavioral;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Map;
/**
* 行为画像 DTO
*
* @author LJWX Health Team
* @since Phase 2 - Sprint 8
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BehavioralProfileDTO {
private Long userId;
private LocalDate profileDate;
// 四类行为画像
private ExerciseHabits exerciseHabits;
private SleepHabits sleepHabits;
private DietPatterns dietPatterns;
private HealthAttention healthAttention;
// 综合评分
private Double overallScore; // 综合行为评分 (0-100)
private String behavioralType; // 行为类型: HEALTH_CONSCIOUS/BALANCED/NEEDS_IMPROVEMENT/AT_RISK
// 元数据
private LocalDate analysisStartDate; // 分析开始日期
private LocalDate analysisEndDate; // 分析结束日期
/**
* 运动习惯
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class ExerciseHabits {
private String activityLevel; // SEDENTARY/LIGHTLY_ACTIVE/MODERATELY_ACTIVE/VERY_ACTIVE
private Double avgDailySteps;
private Integer activeWeekDays;
private String preferredTimeSlot; // MORNING/AFTERNOON/EVENING
private Double consistency; // 0-100
private String trend; // IMPROVING/STABLE/DECLINING
private String recommendation; // 个性化建议
}
/**
* 睡眠习惯
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class SleepHabits {
private String sleepType; // EARLY_BIRD/NIGHT_OWL/NORMAL
private Double avgSleepDuration; // 分钟
private String qualityRating; // EXCELLENT/GOOD/FAIR/POOR
@JsonFormat(pattern = "HH:mm")
private LocalTime avgBedTime;
@JsonFormat(pattern = "HH:mm")
private LocalTime avgWakeTime;
private Double consistency; // 0-100
private String trend; // IMPROVING/STABLE/DECLINING
private String recommendation;
}
/**
* 饮食规律
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class DietPatterns {
private String regularityLevel; // HIGHLY_REGULAR/REGULAR/IRREGULAR/CHAOTIC/DATA_UNAVAILABLE
private Double regularityScore; // 0-100
private Integer avgMealsPerDay;
private Boolean breakfastHabit;
private Map<String, LocalTime> mealTimes; // {breakfast: 07:30, lunch: 12:00, dinner: 18:30}
private String trend;
private String recommendation;
private String remark; // 当前版本说明
}
/**
* 健康关注度
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class HealthAttention {
private String attentionLevel; // HIGHLY_ENGAGED/ENGAGED/PASSIVE/INACTIVE
private Double deviceWearRate; // 设备佩戴率 %
private Integer avgDailyUploads;
private Integer profileViewsPerMonth;
private Double engagementScore; // 0-100
private String trend;
private String recommendation;
}
}
服务架构设计
核心服务: BehavioralProfileService
package com.ljwx.modules.health.service;
import com.ljwx.modules.health.domain.dto.behavioral.BehavioralProfileDTO;
import com.ljwx.modules.health.entity.HealthProfile;
import com.ljwx.modules.health.mapper.HealthProfileMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List;
/**
* 行为画像服务
*
* @author LJWX Health Team
* @since Phase 2 - Sprint 8
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class BehavioralProfileService {
private final HealthProfileMapper healthProfileMapper;
private final ExerciseHabitsAnalyzer exerciseHabitsAnalyzer;
private final SleepHabitsAnalyzer sleepHabitsAnalyzer;
private final DietPatternsAnalyzer dietPatternsAnalyzer;
private final HealthAttentionAnalyzer healthAttentionAnalyzer;
/**
* 生成用户行为画像
*
* @param userId 用户ID
* @param profileDate 画像日期 (默认今天)
* @return 行为画像 DTO
*/
public BehavioralProfileDTO generateBehavioralProfile(Long userId, LocalDate profileDate) {
if (profileDate == null) {
profileDate = LocalDate.now();
}
log.info("开始生成用户行为画像: userId={}, date={}", userId, profileDate);
// 1. 查询近7天健康画像数据 (用于运动、睡眠分析)
LocalDate startDate = profileDate.minusDays(6);
List<HealthProfile> last7DaysProfiles = queryHealthProfiles(userId, startDate, profileDate);
if (last7DaysProfiles.isEmpty()) {
log.warn("用户近7天无健康数据,无法生成行为画像: userId={}", userId);
return null;
}
// 2. 运动习惯分析
BehavioralProfileDTO.ExerciseHabits exerciseHabits =
exerciseHabitsAnalyzer.analyze(userId, last7DaysProfiles);
// 3. 睡眠习惯分析
BehavioralProfileDTO.SleepHabits sleepHabits =
sleepHabitsAnalyzer.analyze(userId, last7DaysProfiles);
// 4. 饮食规律分析
BehavioralProfileDTO.DietPatterns dietPatterns =
dietPatternsAnalyzer.analyze(userId, profileDate);
// 5. 健康关注度分析 (使用近30天数据)
BehavioralProfileDTO.HealthAttention healthAttention =
healthAttentionAnalyzer.analyze(userId, profileDate);
// 6. 计算综合行为评分
Double overallScore = calculateOverallScore(
exerciseHabits, sleepHabits, dietPatterns, healthAttention);
// 7. 确定行为类型
String behavioralType = determineBehavioralType(overallScore);
// 8. 构建 DTO
BehavioralProfileDTO dto = BehavioralProfileDTO.builder()
.userId(userId)
.profileDate(profileDate)
.exerciseHabits(exerciseHabits)
.sleepHabits(sleepHabits)
.dietPatterns(dietPatterns)
.healthAttention(healthAttention)
.overallScore(overallScore)
.behavioralType(behavioralType)
.analysisStartDate(startDate)
.analysisEndDate(profileDate)
.build();
log.info("行为画像生成完成: userId={}, overallScore={}, type={}",
userId, overallScore, behavioralType);
return dto;
}
/**
* 计算综合行为评分
* 权重分配: 运动30% + 睡眠30% + 饮食20% + 关注度20%
*/
private Double calculateOverallScore(
BehavioralProfileDTO.ExerciseHabits exercise,
BehavioralProfileDTO.SleepHabits sleep,
BehavioralProfileDTO.DietPatterns diet,
BehavioralProfileDTO.HealthAttention attention) {
double exerciseScore = mapActivityToScore(exercise.getActivityLevel());
double sleepScore = mapQualityToScore(sleep.getQualityRating());
double dietScore = diet.getRegularityScore() != null ? diet.getRegularityScore() : 0.0;
double attentionScore = attention.getEngagementScore();
return exerciseScore * 0.30 + sleepScore * 0.30 + dietScore * 0.20 + attentionScore * 0.20;
}
/**
* 确定行为类型
*/
private String determineBehavioralType(double score) {
if (score >= 80) return "HEALTH_CONSCIOUS"; // 健康意识强
if (score >= 60) return "BALANCED"; // 平衡型
if (score >= 40) return "NEEDS_IMPROVEMENT"; // 需改善
return "AT_RISK"; // 高风险
}
// ... 其他辅助方法
}
分析器接口设计
package com.ljwx.modules.health.service.analyzer;
/**
* 行为分析器接口
*/
public interface BehaviorAnalyzer<T> {
/**
* 分析行为模式
*
* @param userId 用户ID
* @param data 分析数据
* @return 行为画像结果
*/
T analyze(Long userId, Object data);
}
数据库设计
扩展 t_user_health_profile 表
-- V1.7.0__add_behavioral_profile_fields.sql
ALTER TABLE t_user_health_profile
ADD COLUMN behavioral_profile_json JSON COMMENT '行为画像JSON (存储四类行为数据)',
ADD COLUMN behavioral_score DECIMAL(5,2) COMMENT '综合行为评分 (0-100)',
ADD COLUMN behavioral_type VARCHAR(30) COMMENT '行为类型: HEALTH_CONSCIOUS/BALANCED/NEEDS_IMPROVEMENT/AT_RISK',
ADD COLUMN behavioral_update_time DATETIME COMMENT '行为画像更新时间';
-- 虚拟列索引 (加速行为类型查询)
ALTER TABLE t_user_health_profile
ADD COLUMN behavioral_type_virtual VARCHAR(30)
AS (JSON_UNQUOTE(JSON_EXTRACT(behavioral_profile_json, '$.behavioralType'))) VIRTUAL,
ADD INDEX idx_behavioral_type_virtual (behavioral_type_virtual);
-- 行为评分索引 (支持排名查询)
CREATE INDEX idx_behavioral_score ON t_user_health_profile(behavioral_score DESC);
新增 t_user_profile_view_log 表 (用于健康关注度统计)
CREATE TABLE t_user_profile_view_log (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL COMMENT '用户ID',
customer_id BIGINT NOT NULL COMMENT '客户ID',
view_type VARCHAR(50) COMMENT '查看类型: HEALTH_PROFILE/RISK_PROFILE/BEHAVIORAL_PROFILE',
view_time DATETIME NOT NULL COMMENT '查看时间',
source VARCHAR(50) COMMENT '来源: WEB/MOBILE/API',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_time (user_id, view_time),
INDEX idx_customer_user (customer_id, user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户画像查看日志';
API 设计
BehavioralProfileController.java
package com.ljwx.modules.health.controller;
import com.ljwx.common.api.Result;
import com.ljwx.modules.health.domain.dto.behavioral.BehavioralProfileDTO;
import com.ljwx.modules.health.service.BehavioralProfileService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
/**
* 行为画像 API
*
* @author LJWX Health Team
* @since Phase 2 - Sprint 8
*/
@Tag(name = "行为画像管理", description = "用户行为模式分析与画像生成")
@RestController
@RequestMapping("/api/health/behavioral-profile")
@RequiredArgsConstructor
@Validated
public class BehavioralProfileController {
private final BehavioralProfileService behavioralProfileService;
@Operation(summary = "生成行为画像", description = "基于近期健康数据生成用户行为画像")
@PostMapping("/generate")
public Result<BehavioralProfileDTO> generateBehavioralProfile(
@Parameter(description = "用户ID", required = true) @RequestParam Long userId,
@Parameter(description = "画像日期 (默认今天)")
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate profileDate) {
BehavioralProfileDTO profile = behavioralProfileService.generateBehavioralProfile(userId, profileDate);
if (profile == null) {
return Result.error("用户近期无健康数据,无法生成行为画像");
}
return Result.success(profile);
}
@Operation(summary = "查询行为画像", description = "获取已生成的行为画像数据")
@GetMapping("/query")
public Result<BehavioralProfileDTO> queryBehavioralProfile(
@Parameter(description = "用户ID", required = true) @RequestParam Long userId,
@Parameter(description = "画像日期 (默认今天)")
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate profileDate) {
BehavioralProfileDTO profile = behavioralProfileService.queryBehavioralProfile(userId, profileDate);
if (profile == null) {
return Result.error("未找到行为画像数据");
}
return Result.success(profile);
}
}
数据流架构
┌──────────────────────────────────────────────────────────────────┐
│ 数据采集层 │
│ t_user_health_profile (近7天) + t_sleep_data + t_step_data │
└────────────┬─────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 行为分析层 │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ ExerciseHabits │ │ SleepHabits │ │
│ │ Analyzer │ │ Analyzer │ │
│ └──────────────────┘ └──────────────────┘ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ DietPatterns │ │ HealthAttention │ │
│ │ Analyzer │ │ Analyzer │ │
│ └──────────────────┘ └──────────────────┘ │
└────────────┬─────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 综合评分层 │
│ calculateOverallScore() - 加权平均 │
│ 运动30% + 睡眠30% + 饮食20% + 关注度20% │
└────────────┬─────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 画像存储层 │
│ t_user_health_profile.behavioral_profile_json (JSON) │
│ t_user_health_profile.behavioral_score (评分) │
│ t_user_health_profile.behavioral_type (类型) │
└────────────┬─────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ API 响应层 │
│ BehavioralProfileController → BehavioralProfileDTO │
└──────────────────────────────────────────────────────────────────┘
集成方案
与风险画像集成
行为画像可为风险画像提供行为上下文:
// 示例: 在 RiskProfileService 中引用行为画像
public RiskProfileDTO generateRiskProfile(Long userId, LocalDate profileDate) {
// 1. 生成风险画像
RiskProfileDTO riskProfile = ...;
// 2. 获取行为画像
BehavioralProfileDTO behavioralProfile =
behavioralProfileService.queryBehavioralProfile(userId, profileDate);
// 3. 基于行为画像调整风险建议
if (behavioralProfile != null && "SEDENTARY".equals(behavioralProfile.getExerciseHabits().getActivityLevel())) {
// 久坐用户的心血管风险建议更严格
riskProfile.getCardiovascularRisk().setDetails(
riskProfile.getCardiovascularRisk().getDetails() +
"\n建议: 您的运动量较低,请增加日常活动量以降低心血管风险。"
);
}
return riskProfile;
}
与 AI 健康顾问集成 (Phase 3)
行为画像将作为 AI Prompt 的重要上下文:
用户行为画像:
- 运动习惯: SEDENTARY (日均步数 3200, 活跃天数 2/7)
- 睡眠习惯: NIGHT_OWL (平均入睡时间 01:30, 睡眠质量 FAIR)
- 饮食规律: IRREGULAR (规律性评分 45/100)
- 健康关注度: PASSIVE (设备佩戴率 60%, 月查看次数 2)
基于以上画像,请生成个性化健康建议...
总结
核心交付物
- ✅ 架构设计文档 (本文档, 380+ 行)
- ⏳ 四个行为分析器:
ExerciseHabitsAnalyzer.javaSleepHabitsAnalyzer.javaDietPatternsAnalyzer.javaHealthAttentionAnalyzer.java
- ⏳ BehavioralProfileService.java (核心编排服务)
- ⏳ BehavioralProfileController.java (REST API)
- ⏳ 数据库迁移 (V1.7.0__add_behavioral_profile_fields.sql)
- ⏳ 单元测试 (覆盖率 > 80%)
- ⏳ 集成测试 (端到端测试)
下一步工作
按照 Sprint 8 任务顺序:
- T2.2.2: 实现 ExerciseHabitsAnalyzer (3天)
- T2.2.3: 实现 SleepHabitsAnalyzer (2天)
- T2.2.4: 实现 DietPatternsAnalyzer (2天)
- T2.2.5: 实现 HealthAttentionAnalyzer (1天)
- T2.2.6: 单元测试 (2天)
- T2.2.7: 集成测试 (1天)
文档版本: v1.0 最后更新: 2026-01-20 状态: ✅ 设计评审通过 审核人: LJWX Health Team