本设计文档针对慢病APP增加病人用户健康数据模块的需求进行详细设计。模块包含身高、体重、BMI(自动计算)、血压、血糖(空腹、早餐后、午餐前、午餐后、晚餐前、晚餐后、睡前)、心率等健康指标的记录和管理功能。
重要更新:根据需求,每种类型的健康数据需要独立存储和独立的接口。因此,健康数据模块将被拆分为以下4个独立子模块:
每个子模块独立设计,包含独立的数据库表、数据模型、接口和服务。
// BloodGlucoseType.java
public enum BloodGlucoseType {
FASTING("空腹", "早餐前测量"),
AFTER_BREAKFAST("早餐后", "早餐后2小时测量"),
BEFORE_LUNCH("午餐前", "午餐前测量"),
AFTER_LUNCH("午餐后", "午餐后2小时测量"),
BEFORE_DINNER("晚餐前", "晚餐前测量"),
AFTER_DINNER("晚餐后", "晚餐后2小时测量"),
BEFORE_BED("睡前", "睡前测量");
private final String name;
private final String description;
BloodGlucoseType(String name, String description) {
this.name = name;
this.description = description;
}
// getters
}
健康数据模块
├── 体格数据子模块 (PhysicalData)
│ ├── 数据库表:t_physical_data
│ ├── PO:PhysicalData
│ ├── VO:AddPhysicalDataRequest, PhysicalDataResponse等
│ ├── Controller:PhysicalDataController
│ ├── Service:PhysicalDataService
│ └── Mapper:PhysicalDataMapper
├── 血压数据子模块 (BloodPressureData)
│ ├── 数据库表:t_blood_pressure_data
│ ├── PO:BloodPressureData
│ ├── VO:AddBloodPressureDataRequest, BloodPressureDataResponse等
│ ├── Controller:BloodPressureDataController
│ ├── Service:BloodPressureDataService
│ └── Mapper:BloodPressureDataMapper
├── 血糖数据子模块 (BloodGlucoseData)
│ ├── 数据库表:t_blood_glucose_data
│ ├── PO:BloodGlucoseData
│ ├── VO:AddBloodGlucoseDataRequest, BloodGlucoseDataResponse等
│ ├── Controller:BloodGlucoseDataController
│ ├── Service:BloodGlucoseDataService
│ └── Mapper:BloodGlucoseDataMapper
└── 心率数据子模块 (HeartRateData)
├── 数据库表:t_heart_rate_data
├── PO:HeartRateData
├── VO:AddHeartRateDataRequest, HeartRateDataResponse等
├── Controller:HeartRateDataController
├── Service:HeartRateDataService
└── Mapper:HeartRateDataMapper
BaseQueryRequestBasePageResponse<T>CREATE TABLE t_physical_data (
id BIGINT PRIMARY KEY COMMENT '主键ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
height DECIMAL(5,2) COMMENT '身高(cm)',
weight DECIMAL(5,2) COMMENT '体重(kg)',
measure_time DATETIME NOT NULL COMMENT '测量时间',
create_user BIGINT COMMENT '创建者ID',
create_time DATETIME COMMENT '创建时间',
update_user BIGINT COMMENT '更新者ID',
update_time DATETIME COMMENT '更新时间',
version INT DEFAULT 0 COMMENT '乐观锁版本号'
) COMMENT '体格数据表';
-- 索引设计
CREATE INDEX idx_physical_user_measure_time ON t_physical_data(user_id, measure_time);
CREATE INDEX idx_physical_user_id ON t_physical_data(user_id);
CREATE TABLE t_blood_pressure_data (
id BIGINT PRIMARY KEY COMMENT '主键ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
systolic_pressure INT COMMENT '收缩压(mmHg)',
diastolic_pressure INT COMMENT '舒张压(mmHg)',
measure_time DATETIME NOT NULL COMMENT '测量时间',
create_user BIGINT COMMENT '创建者ID',
create_time DATETIME COMMENT '创建时间',
update_user BIGINT COMMENT '更新者ID',
update_time DATETIME COMMENT '更新时间',
version INT DEFAULT 0 COMMENT '乐观锁版本号'
) COMMENT '血压数据表';
-- 索引设计
CREATE INDEX idx_bp_user_measure_time ON t_blood_pressure_data(user_id, measure_time);
CREATE INDEX idx_bp_user_id ON t_blood_pressure_data(user_id);
CREATE TABLE t_blood_glucose_data (
id BIGINT PRIMARY KEY COMMENT '主键ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
fasting_blood_glucose DECIMAL(4,2) COMMENT '空腹血糖(mmol/L)',
after_breakfast_blood_glucose DECIMAL(4,2) COMMENT '早餐后血糖(mmol/L)',
before_lunch_blood_glucose DECIMAL(4,2) COMMENT '午餐前血糖(mmol/L)',
after_lunch_blood_glucose DECIMAL(4,2) COMMENT '午餐后血糖(mmol/L)',
before_dinner_blood_glucose DECIMAL(4,2) COMMENT '晚餐前血糖(mmol/L)',
after_dinner_blood_glucose DECIMAL(4,2) COMMENT '晚餐后血糖(mmol/L)',
before_bed_blood_glucose DECIMAL(4,2) COMMENT '睡前血糖(mmol/L)',
measure_time DATETIME NOT NULL COMMENT '测量时间',
create_user BIGINT COMMENT '创建者ID',
create_time DATETIME COMMENT '创建时间',
update_user BIGINT COMMENT '更新者ID',
update_time DATETIME COMMENT '更新时间',
version INT DEFAULT 0 COMMENT '乐观锁版本号'
) COMMENT '血糖数据表';
-- 索引设计
CREATE INDEX idx_bg_user_measure_time ON t_blood_glucose_data(user_id, measure_time);
CREATE INDEX idx_bg_user_id ON t_blood_glucose_data(user_id);
CREATE TABLE t_heart_rate_data (
id BIGINT PRIMARY KEY COMMENT '主键ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
heart_rate INT COMMENT '心率(次/分钟)',
measure_time DATETIME NOT NULL COMMENT '测量时间',
create_user BIGINT COMMENT '创建者ID',
create_time DATETIME COMMENT '创建时间',
update_user BIGINT COMMENT '更新者ID',
update_time DATETIME COMMENT '更新时间',
version INT DEFAULT 0 COMMENT '乐观锁版本号'
) COMMENT '心率数据表';
-- 索引设计
CREATE INDEX idx_hr_user_measure_time ON t_heart_rate_data(user_id, measure_time);
CREATE INDEX idx_hr_user_id ON t_heart_rate_data(user_id);
id:主键,使用雪花算法生成user_id:关联用户IDmeasure_time:数据测量时间height(身高), weight(体重)systolic_pressure(收缩压), diastolic_pressure(舒张压)fasting_blood_glucose(空腹血糖), after_breakfast_blood_glucose(早餐后血糖), before_lunch_blood_glucose(午餐前血糖), after_lunch_blood_glucose(午餐后血糖), before_dinner_blood_glucose(晚餐前血糖), after_dinner_blood_glucose(晚餐后血糖), before_bed_blood_glucose(睡前血糖)heart_rate(心率)// PhysicalData.java
@TableName("t_physical_data")
public class PhysicalData extends BaseEntity {
@TableField("user_id")
private Long userId;
@TableField("height")
private BigDecimal height;
@TableField("weight")
private BigDecimal weight;
@TableField("measure_time")
private LocalDateTime measureTime;
// getters and setters
}
// BloodPressureData.java
@TableName("t_blood_pressure_data")
public class BloodPressureData extends BaseEntity {
@TableField("user_id")
private Long userId;
@TableField("systolic_pressure")
private Integer systolicPressure;
@TableField("diastolic_pressure")
private Integer diastolicPressure;
@TableField("measure_time")
private LocalDateTime measureTime;
// getters and setters
}
// BloodGlucoseData.java
@TableName("t_blood_glucose_data")
public class BloodGlucoseData extends BaseEntity {
@TableField("user_id")
private Long userId;
@TableField("fasting_blood_glucose")
private BigDecimal fastingBloodGlucose;
@TableField("after_breakfast_blood_glucose")
private BigDecimal afterBreakfastBloodGlucose;
@TableField("before_lunch_blood_glucose")
private BigDecimal beforeLunchBloodGlucose;
@TableField("after_lunch_blood_glucose")
private BigDecimal afterLunchBloodGlucose;
@TableField("before_dinner_blood_glucose")
private BigDecimal beforeDinnerBloodGlucose;
@TableField("after_dinner_blood_glucose")
private BigDecimal afterDinnerBloodGlucose;
@TableField("before_bed_blood_glucose")
private BigDecimal beforeBedBloodGlucose;
@TableField("measure_time")
private LocalDateTime measureTime;
// getters and setters
}
// HeartRateData.java
@TableName("t_heart_rate_data")
public class HeartRateData extends BaseEntity {
@TableField("user_id")
private Long userId;
@TableField("heart_rate")
private Integer heartRate;
@TableField("measure_time")
private LocalDateTime measureTime;
// getters and setters
}
// BaseQueryRequest.java
@Schema(description = "基础查询请求")
public class BaseQueryRequest {
@Schema(description = "页码", minimum = "1", defaultValue = "1")
@Min(1)
private Integer pageNum = 1;
@Schema(description = "每页大小", minimum = "1", maximum = "100", defaultValue = "10")
@Min(1) @Max(100)
private Integer pageSize = 10;
@Schema(description = "开始时间")
private LocalDateTime startTime;
@Schema(description = "结束时间")
private LocalDateTime endTime;
// getters and setters
}
// AddPhysicalDataRequest.java
@Schema(description = "添加体格数据请求")
public class AddPhysicalDataRequest {
@Schema(description = "身高(cm)", minimum = "100", maximum = "250")
@DecimalMin("100") @DecimalMax("250")
private BigDecimal height;
@Schema(description = "体重(kg)", minimum = "20", maximum = "300")
@DecimalMin("20") @DecimalMax("300")
private BigDecimal weight;
@Schema(description = "测量时间")
@NotNull
private LocalDateTime measureTime;
// getters and setters
}
// PhysicalDataResponse.java
@Schema(description = "体格数据响应")
public class PhysicalDataResponse {
@Schema(description = "记录ID")
private Long id;
@Schema(description = "身高(cm)")
private BigDecimal height;
@Schema(description = "体重(kg)")
private BigDecimal weight;
@Schema(description = "BMI")
private BigDecimal bmi;
@Schema(description = "测量时间")
private LocalDateTime measureTime;
@Schema(description = "创建时间")
private LocalDateTime createTime;
// getters and setters
}
// AddBloodPressureDataRequest.java
@Schema(description = "添加血压数据请求")
public class AddBloodPressureDataRequest {
@Schema(description = "收缩压(mmHg)", minimum = "60", maximum = "250")
@Min(60) @Max(250)
private Integer systolicPressure;
@Schema(description = "舒张压(mmHg)", minimum = "40", maximum = "150")
@Min(40) @Max(150)
private Integer diastolicPressure;
@Schema(description = "测量时间")
@NotNull
private LocalDateTime measureTime;
// getters and setters
}
// BloodPressureDataResponse.java
@Schema(description = "血压数据响应")
public class BloodPressureDataResponse {
@Schema(description = "记录ID")
private Long id;
@Schema(description = "收缩压(mmHg)")
private Integer systolicPressure;
@Schema(description = "舒张压(mmHg)")
private Integer diastolicPressure;
@Schema(description = "测量时间")
private LocalDateTime measureTime;
@Schema(description = "创建时间")
private LocalDateTime createTime;
// getters and setters
}
// AddBloodGlucoseDataRequest.java
@Schema(description = "添加血糖数据请求")
public class AddBloodGlucoseDataRequest {
@Schema(description = "空腹血糖(mmol/L)", minimum = "1.0", maximum = "30.0")
@DecimalMin("1.0") @DecimalMax("30.0")
private BigDecimal fastingBloodGlucose;
@Schema(description = "早餐后血糖(mmol/L)", minimum = "1.0", maximum = "30.0")
@DecimalMin("1.0") @DecimalMax("30.0")
private BigDecimal afterBreakfastBloodGlucose;
@Schema(description = "午餐前血糖(mmol/L)", minimum = "1.0", maximum = "30.0")
@DecimalMin("1.0") @DecimalMax("30.0")
private BigDecimal beforeLunchBloodGlucose;
@Schema(description = "午餐后血糖(mmol/L)", minimum = "1.0", maximum = "30.0")
@DecimalMin("1.0") @DecimalMax("30.0")
private BigDecimal afterLunchBloodGlucose;
@Schema(description = "晚餐前血糖(mmol/L)", minimum = "1.0", maximum = "30.0")
@DecimalMin("1.0") @DecimalMax("30.0")
private BigDecimal beforeDinnerBloodGlucose;
@Schema(description = "晚餐后血糖(mmol/L)", minimum = "1.0", maximum = "30.0")
@DecimalMin("1.0") @DecimalMax("30.0")
private BigDecimal afterDinnerBloodGlucose;
@Schema(description = "睡前血糖(mmol/L)", minimum = "1.0", maximum = "30.0")
@DecimalMin("1.0") @DecimalMax("30.0")
private BigDecimal beforeBedBloodGlucose;
@Schema(description = "测量时间")
@NotNull
private LocalDateTime measureTime;
// getters and setters
}
// BloodGlucoseDataResponse.java
@Schema(description = "血糖数据响应")
public class BloodGlucoseDataResponse {
@Schema(description = "记录ID")
private Long id;
@Schema(description = "空腹血糖(mmol/L)")
private BigDecimal fastingBloodGlucose;
@Schema(description = "早餐后血糖(mmol/L)")
private BigDecimal afterBreakfastBloodGlucose;
@Schema(description = "午餐前血糖(mmol/L)")
private BigDecimal beforeLunchBloodGlucose;
@Schema(description = "午餐后血糖(mmol/L)")
private BigDecimal afterLunchBloodGlucose;
@Schema(description = "晚餐前血糖(mmol/L)")
private BigDecimal beforeDinnerBloodGlucose;
@Schema(description = "晚餐后血糖(mmol/L)")
private BigDecimal afterDinnerBloodGlucose;
@Schema(description = "睡前血糖(mmol/L)")
private BigDecimal beforeBedBloodGlucose;
@Schema(description = "测量时间")
private LocalDateTime measureTime;
@Schema(description = "创建时间")
private LocalDateTime createTime;
// getters and setters
}
// AddHeartRateDataRequest.java
@Schema(description = "添加心率数据请求")
public class AddHeartRateDataRequest {
@Schema(description = "心率(次/分钟)", minimum = "30", maximum = "200")
@Min(30) @Max(200)
private Integer heartRate;
@Schema(description = "测量时间")
@NotNull
private LocalDateTime measureTime;
// getters and setters
}
// HeartRateDataResponse.java
@Schema(description = "心率数据响应")
public class HeartRateDataResponse {
@Schema(description = "记录ID")
private Long id;
@Schema(description = "心率(次/分钟)")
private Integer heartRate;
@Schema(description = "测量时间")
private LocalDateTime measureTime;
@Schema(description = "创建时间")
private LocalDateTime createTime;
// getters and setters
}
@RestController
@RequestMapping("/physical-data")
@Tag(name = "体格数据管理", description = "病人体格数据相关接口")
public class PhysicalDataController {
@Autowired
private PhysicalDataService physicalDataService;
@PostMapping("/add")
@Operation(summary = "添加体格数据")
public R<Void> addPhysicalData(@RequestBody @Valid AddPhysicalDataRequest request) {
physicalDataService.addPhysicalData(request);
return R.success(SuccessResultCode.SUCCESS, "添加成功", null);
}
@PostMapping("/list")
@Operation(summary = "查询体格数据列表")
public R<Page<PhysicalDataResponse>> listPhysicalData(@RequestBody @Valid BaseQueryRequest request) {
Page<PhysicalDataResponse> response = physicalDataService.listPhysicalData(request);
return R.success(SuccessResultCode.SUCCESS, "查询成功", response);
}
@GetMapping("/bmi")
@Operation(summary = "计算BMI")
public R<BigDecimal> calculateBMI(@RequestParam @DecimalMin("100") @DecimalMax("250") BigDecimal height,
@RequestParam @DecimalMin("20") @DecimalMax("300") BigDecimal weight) {
BigDecimal bmi = physicalDataService.calculateBMI(height, weight);
return R.success(SuccessResultCode.SUCCESS, "计算成功", bmi);
}
}
public interface PhysicalDataService {
void addPhysicalData(AddPhysicalDataRequest request);
Page<PhysicalDataResponse> listPhysicalData(BaseQueryRequest request);
BigDecimal calculateBMI(BigDecimal height, BigDecimal weight);
}
@Service
public class PhysicalDataServiceImpl implements PhysicalDataService {
@Autowired
private PhysicalDataMapper physicalDataMapper;
@Override
public void addPhysicalData(AddPhysicalDataRequest request) {
Long userId = getCurrentUserId();
PhysicalData physicalData = new PhysicalData();
BeanUtils.copyProperties(request, physicalData);
physicalData.setUserId(userId);
physicalDataMapper.insert(physicalData);
}
@Override
public Page<PhysicalDataResponse> listPhysicalData(BaseQueryRequest request) {
Long userId = getCurrentUserId();
Page<PhysicalData> page = new Page<>(request.getPageNum(), request.getPageSize());
LambdaQueryWrapper<PhysicalData> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PhysicalData::getUserId, userId)
.ge(request.getStartTime() != null, PhysicalData::getMeasureTime, request.getStartTime())
.le(request.getEndTime() != null, PhysicalData::getMeasureTime, request.getEndTime())
.orderByDesc(PhysicalData::getMeasureTime);
Page<PhysicalData> result = physicalDataMapper.selectPage(page, wrapper);
// 转换为响应对象,计算BMI
List<PhysicalDataResponse> responses = result.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
Page<PhysicalDataResponse> responsePage = new Page<>();
responsePage.setRecords(responses);
responsePage.setCurrent(result.getCurrent());
responsePage.setSize(result.getSize());
responsePage.setTotal(result.getTotal());
return responsePage;
}
@Override
public BigDecimal calculateBMI(BigDecimal height, BigDecimal weight) {
if (height == null || weight == null || height.compareTo(BigDecimal.ZERO) <= 0) {
return BigDecimal.ZERO;
}
// BMI = 体重(kg) / [身高(m)]^2
BigDecimal heightInMeters = height.divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
return weight.divide(heightInMeters.pow(2), 2, RoundingMode.HALF_UP);
}
private PhysicalDataResponse convertToResponse(PhysicalData physicalData) {
PhysicalDataResponse response = new PhysicalDataResponse();
BeanUtils.copyProperties(physicalData, response);
// 计算BMI
response.setBmi(calculateBMI(physicalData.getHeight(), physicalData.getWeight()));
return response;
}
private Long getCurrentUserId() {
// 从安全上下文中获取当前用户ID
return 1L; // 临时实现
}
}
@Mapper
public interface PhysicalDataMapper extends BaseMapper<PhysicalData> {
}
@RestController
@RequestMapping("/blood-pressure-data")
@Tag(name = "血压数据管理", description = "病人血压数据相关接口")
public class BloodPressureDataController {
@Autowired
private BloodPressureDataService bloodPressureDataService;
@PostMapping("/add")
@Operation(summary = "添加血压数据")
public R<Void> addBloodPressureData(@RequestBody @Valid AddBloodPressureDataRequest request) {
bloodPressureDataService.addBloodPressureData(request);
return R.success(SuccessResultCode.SUCCESS, "添加成功", null);
}
@PostMapping("/list")
@Operation(summary = "查询血压数据列表")
public R<Page<BloodPressureDataResponse>> listBloodPressureData(@RequestBody @Valid BaseQueryRequest request) {
Page<BloodPressureDataResponse> response = bloodPressureDataService.listBloodPressureData(request);
return R.success(SuccessResultCode.SUCCESS, "查询成功", response);
}
}
public interface BloodPressureDataService {
void addBloodPressureData(AddBloodPressureDataRequest request);
Page<BloodPressureDataResponse> listBloodPressureData(BaseQueryRequest request);
}
@Service
public class BloodPressureDataServiceImpl implements BloodPressureDataService {
@Autowired
private BloodPressureDataMapper bloodPressureDataMapper;
@Override
public void addBloodPressureData(AddBloodPressureDataRequest request) {
Long userId = getCurrentUserId();
BloodPressureData bloodPressureData = new BloodPressureData();
BeanUtils.copyProperties(request, bloodPressureData);
bloodPressureData.setUserId(userId);
bloodPressureDataMapper.insert(bloodPressureData);
}
@Override
public Page<BloodPressureDataResponse> listBloodPressureData(BaseQueryRequest request) {
Long userId = getCurrentUserId();
Page<BloodPressureData> page = new Page<>(request.getPageNum(), request.getPageSize());
LambdaQueryWrapper<BloodPressureData> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BloodPressureData::getUserId, userId)
.ge(request.getStartTime() != null, BloodPressureData::getMeasureTime, request.getStartTime())
.le(request.getEndTime() != null, BloodPressureData::getMeasureTime, request.getEndTime())
.orderByDesc(BloodPressureData::getMeasureTime);
Page<BloodPressureData> result = bloodPressureDataMapper.selectPage(page, wrapper);
List<BloodPressureDataResponse> responses = result.getRecords().stream()
.map(record -> {
BloodPressureDataResponse response = new BloodPressureDataResponse();
BeanUtils.copyProperties(record, response);
return response;
})
.collect(Collectors.toList());
Page<BloodPressureDataResponse> responsePage = new Page<>();
responsePage.setRecords(responses);
responsePage.setCurrent(result.getCurrent());
responsePage.setSize(result.getSize());
responsePage.setTotal(result.getTotal());
return responsePage;
}
private Long getCurrentUserId() {
// 从安全上下文中获取当前用户ID
return 1L; // 临时实现
}
}
@Mapper
public interface BloodPressureDataMapper extends BaseMapper<BloodPressureData> {
}
@RestController
@RequestMapping("/blood-glucose-data")
@Tag(name = "血糖数据管理", description = "病人血糖数据相关接口")
public class BloodGlucoseDataController {
@Autowired
private BloodGlucoseDataService bloodGlucoseDataService;
@PostMapping("/add")
@Operation(summary = "添加血糖数据")
public R<Void> addBloodGlucoseData(@RequestBody @Valid AddBloodGlucoseDataRequest request) {
bloodGlucoseDataService.addBloodGlucoseData(request);
return R.success(SuccessResultCode.SUCCESS, "添加成功", null);
}
@PostMapping("/list")
@Operation(summary = "查询血糖数据列表")
public R<Page<BloodGlucoseDataResponse>> listBloodGlucoseData(@RequestBody @Valid BaseQueryRequest request) {
Page<BloodGlucoseDataResponse> response = bloodGlucoseDataService.listBloodGlucoseData(request);
return R.success(SuccessResultCode.SUCCESS, "查询成功", response);
}
}
public interface BloodGlucoseDataService {
void addBloodGlucoseData(AddBloodGlucoseDataRequest request);
Page<BloodGlucoseDataResponse> listBloodGlucoseData(BaseQueryRequest request);
}
@Service
public class BloodGlucoseDataServiceImpl implements BloodGlucoseDataService {
@Autowired
private BloodGlucoseDataMapper bloodGlucoseDataMapper;
@Override
public void addBloodGlucoseData(AddBloodGlucoseDataRequest request) {
Long userId = getCurrentUserId();
BloodGlucoseData bloodGlucoseData = new BloodGlucoseData();
BeanUtils.copyProperties(request, bloodGlucoseData);
bloodGlucoseData.setUserId(userId);
bloodGlucoseDataMapper.insert(bloodGlucoseData);
}
@Override
public Page<BloodGlucoseDataResponse> listBloodGlucoseData(BaseQueryRequest request) {
Long userId = getCurrentUserId();
Page<BloodGlucoseData> page = new Page<>(request.getPageNum(), request.getPageSize());
LambdaQueryWrapper<BloodGlucoseData> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BloodGlucoseData::getUserId, userId)
.ge(request.getStartTime() != null, BloodGlucoseData::getMeasureTime, request.getStartTime())
.le(request.getEndTime() != null, BloodGlucoseData::getMeasureTime, request.getEndTime())
.orderByDesc(BloodGlucoseData::getMeasureTime);
Page<BloodGlucoseData> result = bloodGlucoseDataMapper.selectPage(page, wrapper);
List<BloodGlucoseDataResponse> responses = result.getRecords().stream()
.map(record -> {
BloodGlucoseDataResponse response = new BloodGlucoseDataResponse();
BeanUtils.copyProperties(record, response);
return response;
})
.collect(Collectors.toList());
Page<BloodGlucoseDataResponse> responsePage = new Page<>();
responsePage.setRecords(responses);
responsePage.setCurrent(result.getCurrent());
responsePage.setSize(result.getSize());
responsePage.setTotal(result.getTotal());
return responsePage;
}
private Long getCurrentUserId() {
// 从安全上下文中获取当前用户ID
return 1L; // 临时实现
}
}
@Mapper
public interface BloodGlucoseDataMapper extends BaseMapper<BloodGlucoseData> {
}
@RestController
@RequestMapping("/heart-rate-data")
@Tag(name = "心率数据管理", description = "病人心率数据相关接口")
public class HeartRateDataController {
@Autowired
private HeartRateDataService heartRateDataService;
@PostMapping("/add")
@Operation(summary = "添加心率数据")
public R<Void> addHeartRateData(@RequestBody @Valid AddHeartRateDataRequest request) {
heartRateDataService.addHeartRateData(request);
return R.success(SuccessResultCode.SUCCESS, "添加成功", null);
}
@PostMapping("/list")
@Operation(summary = "查询心率数据列表")
public R<Page<HeartRateDataResponse>> listHeartRateData(@RequestBody @Valid BaseQueryRequest request) {
Page<HeartRateDataResponse> response = heartRateDataService.listHeartRateData(request);
return R.success(SuccessResultCode.SUCCESS, "查询成功", response);
}
}
public interface HeartRateDataService {
void addHeartRateData(AddHeartRateDataRequest request);
Page<HeartRateDataResponse> listHeartRateData(BaseQueryRequest request);
}
@Service
public class HeartRateDataServiceImpl implements HeartRateDataService {
@Autowired
private HeartRateDataMapper heartRateDataMapper;
@Override
public void addHeartRateData(AddHeartRateDataRequest request) {
Long userId = getCurrentUserId();
HeartRateData heartRateData = new HeartRateData();
BeanUtils.copyProperties(request, heartRateData);
heartRateData.setUserId(userId);
heartRateDataMapper.insert(heartRateData);
}
@Override
public Page<HeartRateDataResponse> listHeartRateData(BaseQueryRequest request) {
Long userId = getCurrentUserId();
Page<HeartRateData> page = new Page<>(request.getPageNum(), request.getPageSize());
LambdaQueryWrapper<HeartRateData> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HeartRateData::getUserId, userId)
.ge(request.getStartTime() != null, HeartRateData::getMeasureTime, request.getStartTime())
.le(request.getEndTime() != null, HeartRateData::getMeasureTime, request.getEndTime())
.orderByDesc(HeartRateData::getMeasureTime);
Page<HeartRateData> result = heartRateDataMapper.selectPage(page, wrapper);
List<HeartRateDataResponse> responses = result.getRecords().stream()
.map(record -> {
HeartRateDataResponse response = new HeartRateDataResponse();
BeanUtils.copyProperties(record, response);
return response;
})
.collect(Collectors.toList());
Page<HeartRateDataResponse> responsePage = new Page<>();
responsePage.setRecords(responses);
responsePage.setCurrent(result.getCurrent());
responsePage.setSize(result.getSize());
responsePage.setTotal(result.getTotal());
return responsePage;
}
private Long getCurrentUserId() {
// 从安全上下文中获取当前用户ID
return 1L; // 临时实现
}
}
@Mapper
public interface HeartRateDataMapper extends BaseMapper<HeartRateData> {
}
本设计文档为第一阶段输出,后续阶段将包括:
每个阶段都会生成独立的中间文件,确保设计过程可审查和可追溯。
这样可以确保核心功能(BMI计算)优先实现,同时为其他模块提供参考模板。
本设计遵循项目现有规范,提供了完整的健康数据模块设计方案。设计考虑了数据完整性、安全性、性能和扩展性,为慢病APP的健康数据管理提供了坚实的基础。
关键特性:
设计优势: