|
|
@@ -14,15 +14,15 @@
|
|
|
|--------|------|------|
|
|
|
| id | BIGINT(20) | 主键ID,使用雪花算法(MyBatis-Plus `ASSIGN_ID`) |
|
|
|
| patient_user_id | BIGINT(20) | 患者用户ID,每个患者只有一条记录 |
|
|
|
-| is_notification_enabled | TINYINT(1) | 是否启用消息通知总开关 (0-禁用, 1-启用) |
|
|
|
-| is_subscription_available | TINYINT(1) | 一次性订阅开关,服务器每发送消息后需重新申请用户授权 (0-需要重新授权, 1-已授权可发送) |
|
|
|
-| is_blood_pressure_enabled | TINYINT(1) | 测量血压提醒开关 (0-禁用, 1-启用) |
|
|
|
+| is_notification_enabled | TINYINT(1) | 是否启用消息通知总开关 (0-禁用, 1-启用)。在 Java 实体中以 `Byte` 类型保存,服务层对其值作 Boolean 转换(1=true)。 |
|
|
|
+| is_subscription_available | TINYINT(1) | 一次性订阅开关,服务器每发送消息后需重新申请用户授权 (0-需要重新授权, 1-已授权可发送)。在实体中为 `Byte`,对外 VO 封装为 `Boolean`。 |
|
|
|
+| is_blood_pressure_enabled | TINYINT(1) | 测量血压提醒开关 (0-禁用, 1-启用)。实体字段为 `Byte`,响应层转为 `Boolean`。 |
|
|
|
| blood_pressure_times | TEXT | 测量血压的时间点(JSON格式存储,参考用药管理功能设计文档) |
|
|
|
-| is_blood_sugar_enabled | TINYINT(1) | 测量血糖提醒开关 (0-禁用, 1-启用) |
|
|
|
+| is_blood_sugar_enabled | TINYINT(1) | 测量血糖提醒开关 (0-禁用, 1-启用)。实体字段为 `Byte`,响应层转为 `Boolean`。 |
|
|
|
| blood_sugar_times | TEXT | 测量血糖的时间点(JSON格式存储) |
|
|
|
-| is_heart_rate_enabled | TINYINT(1) | 测量心率提醒开关 (0-禁用, 1-启用) |
|
|
|
+| is_heart_rate_enabled | TINYINT(1) | 测量心率提醒开关 (0-禁用, 1-启用)。实体字段为 `Byte`,响应层转为 `Boolean`。 |
|
|
|
| heart_rate_times | TEXT | 测量心率的时间点(JSON格式存储) |
|
|
|
-| is_medication_enabled | TINYINT(1) | 用药提醒开关 (0-禁用, 1-启用) |
|
|
|
+| is_medication_enabled | TINYINT(1) | 用药提醒开关 (0-禁用, 1-启用)。实体字段为 `Byte`,响应层转为 `Boolean`。 |
|
|
|
| version | INT(11) | 版本号(乐观锁) |
|
|
|
| create_user | BIGINT(20) | 创建者ID |
|
|
|
| create_time | DATETIME | 创建时间,默认值CURRENT_TIMESTAMP |
|
|
|
@@ -63,7 +63,7 @@ CREATE TABLE `t_patient_reminder` (
|
|
|
|
|
|
## 3. 枚举类型设计
|
|
|
|
|
|
-本功能设计中不使用枚举类型,所有提醒类型直接作为字段存储在患者提醒设置表中。
|
|
|
+本功能设计中不使用枚举类型,所有提醒类型直接作为字段存储在患者提醒设置表中。注意:实体层字段在数据库中以 `TINYINT(1)` 保存(Java 实体使用 `Byte`),但对外 VO 使用 `Boolean`,并在 Service 层做相应的转换。
|
|
|
return code == null ? null : ReminderType.fromCode(code);
|
|
|
}
|
|
|
|
|
|
@@ -107,14 +107,17 @@ public class PatientReminder extends BaseEntity {
|
|
|
|
|
|
@Schema(description = "是否启用消息通知总开关 (0-禁用, 1-启用)")
|
|
|
@TableField("is_notification_enabled")
|
|
|
+ // 注意:数据库中为 TINYINT(1),实体类 `PatientReminder` 使用 `Byte`,响应 VO 仍是 Boolean
|
|
|
private Boolean notificationEnabled;
|
|
|
|
|
|
@Schema(description = "一次性订阅开关 (0-需要重新授权, 1-已授权可发送)")
|
|
|
@TableField("is_subscription_available")
|
|
|
+ // 注意:数据库中为 TINYINT(1),实体类 `PatientReminder` 使用 `Byte`,响应 VO 仍是 Boolean
|
|
|
private Boolean subscriptionAvailable;
|
|
|
|
|
|
@Schema(description = "测量血压提醒开关 (0-禁用, 1-启用)")
|
|
|
@TableField("is_blood_pressure_enabled")
|
|
|
+ // 注意:数据库中为 TINYINT(1),实体类 `PatientReminder` 使用 `Byte`,响应 VO 仍是 Boolean
|
|
|
private Boolean bloodPressureEnabled;
|
|
|
|
|
|
@Schema(description = "测量血压的时间点(JSON格式存储)")
|
|
|
@@ -123,6 +126,7 @@ public class PatientReminder extends BaseEntity {
|
|
|
|
|
|
@Schema(description = "测量血糖提醒开关 (0-禁用, 1-启用)")
|
|
|
@TableField("is_blood_sugar_enabled")
|
|
|
+ // 注意:数据库中为 TINYINT(1),实体类 `PatientReminder` 使用 `Byte`,响应 VO 仍是 Boolean
|
|
|
private Boolean bloodSugarEnabled;
|
|
|
|
|
|
@Schema(description = "测量血糖的时间点(JSON格式存储)")
|
|
|
@@ -131,6 +135,7 @@ public class PatientReminder extends BaseEntity {
|
|
|
|
|
|
@Schema(description = "测量心率提醒开关 (0-禁用, 1-启用)")
|
|
|
@TableField("is_heart_rate_enabled")
|
|
|
+ // 注意:数据库中为 TINYINT(1),实体类 `PatientReminder` 使用 `Byte`,响应 VO 仍是 Boolean
|
|
|
private Boolean heartRateEnabled;
|
|
|
|
|
|
@Schema(description = "测量心率的时间点(JSON格式存储)")
|
|
|
@@ -139,6 +144,7 @@ public class PatientReminder extends BaseEntity {
|
|
|
|
|
|
@Schema(description = "用药提醒开关 (0-禁用, 1-启用)")
|
|
|
@TableField("is_medication_enabled")
|
|
|
+ // 注意:数据库中为 TINYINT(1),实体类 `PatientReminder` 使用 `Byte`,响应 VO 仍是 Boolean
|
|
|
private Boolean medicationEnabled;
|
|
|
}
|
|
|
```
|
|
|
@@ -154,6 +160,7 @@ package work.baiyun.chronicdiseaseapp.model.vo;
|
|
|
import io.swagger.v3.oas.annotations.media.Schema;
|
|
|
import lombok.Data;
|
|
|
import java.util.List;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
|
|
|
@Schema(description = "患者提醒设置请求")
|
|
|
@Data
|
|
|
@@ -307,8 +314,8 @@ public interface PatientReminderMapper extends BaseMapper<PatientReminder> {
|
|
|
package work.baiyun.chronicdiseaseapp.service;
|
|
|
|
|
|
import work.baiyun.chronicdiseaseapp.model.vo.PatientReminderOverviewResponse;
|
|
|
-import work.baiyun.chronicdiseaseapp.model.vo.CreatePatientReminderRequest;
|
|
|
-import work.baiyun.chronicdiseaseapp.model.vo.UpdatePatientReminderRequest;
|
|
|
+import work.baiyun.chronicdiseaseapp.model.vo.PatientReminderRequest;
|
|
|
+// Update operations are handled by savePatientReminder, no separate UpdatePatientReminderRequest implementation is required.
|
|
|
|
|
|
public interface PatientReminderService {
|
|
|
/**
|
|
|
@@ -319,7 +326,7 @@ public interface PatientReminderService {
|
|
|
/**
|
|
|
* 保存患者提醒设置(创建或更新)
|
|
|
*/
|
|
|
- void savePatientReminder(CreatePatientReminderRequest request);
|
|
|
+ void savePatientReminder(PatientReminderRequest request);
|
|
|
|
|
|
/**
|
|
|
* 删除患者提醒设置
|
|
|
@@ -334,7 +341,8 @@ public interface PatientReminderService {
|
|
|
// PatientReminderServiceImpl.java
|
|
|
package work.baiyun.chronicdiseaseapp.service.impl;
|
|
|
|
|
|
-import com.alibaba.fastjson.JSON;
|
|
|
+import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
+import work.baiyun.chronicdiseaseapp.util.JsonUtils;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
@@ -343,7 +351,7 @@ import work.baiyun.chronicdiseaseapp.mapper.PatientReminderMapper;
|
|
|
import work.baiyun.chronicdiseaseapp.model.po.PatientReminder;
|
|
|
import work.baiyun.chronicdiseaseapp.model.vo.PatientReminderOverviewResponse;
|
|
|
import work.baiyun.chronicdiseaseapp.model.vo.PatientReminderResponse;
|
|
|
-import work.baiyun.chronicdiseaseapp.model.vo.CreatePatientReminderRequest;
|
|
|
+import work.baiyun.chronicdiseaseapp.model.vo.PatientReminderRequest;
|
|
|
import work.baiyun.chronicdiseaseapp.service.PatientReminderService;
|
|
|
import work.baiyun.chronicdiseaseapp.util.SecurityUtils;
|
|
|
import java.util.List;
|
|
|
@@ -357,8 +365,11 @@ public class PatientReminderServiceImpl implements PatientReminderService {
|
|
|
@Override
|
|
|
public PatientReminderOverviewResponse getReminderOverview() {
|
|
|
Long userId = SecurityUtils.getCurrentUserId();
|
|
|
+ // 注意:getReminderOverview 是只读方法,不会修改提醒设置;保存逻辑和订阅清理在 savePatientReminder 中完成。
|
|
|
|
|
|
- PatientReminder patientReminder = patientReminderMapper.selectByPatientUserId(userId);
|
|
|
+ PatientReminder patientReminder = patientReminderMapper.selectOne(
|
|
|
+ new QueryWrapper<PatientReminder>().eq("patient_user_id", userId)
|
|
|
+ );
|
|
|
|
|
|
PatientReminderOverviewResponse response = new PatientReminderOverviewResponse();
|
|
|
|
|
|
@@ -366,18 +377,29 @@ public class PatientReminderServiceImpl implements PatientReminderService {
|
|
|
PatientReminderResponse reminderResponse = new PatientReminderResponse();
|
|
|
BeanUtils.copyProperties(patientReminder, reminderResponse);
|
|
|
reminderResponse.setId(patientReminder.getId().toString());
|
|
|
- reminderResponse.setBloodPressureTimes(JSON.parseArray(patientReminder.getBloodPressureTimes(), String.class));
|
|
|
- reminderResponse.setBloodSugarTimes(JSON.parseArray(patientReminder.getBloodSugarTimes(), String.class));
|
|
|
- reminderResponse.setHeartRateTimes(JSON.parseArray(patientReminder.getHeartRateTimes(), String.class));
|
|
|
+ reminderResponse.setPatientUserId(patientReminder.getPatientUserId().toString());
|
|
|
+ // 通过 byte->Boolean 映射:1 -> true, others -> false
|
|
|
+ reminderResponse.setNotificationEnabled(patientReminder.getNotificationEnabled() != null && patientReminder.getNotificationEnabled() == 1);
|
|
|
+ reminderResponse.setSubscriptionAvailable(patientReminder.getSubscriptionAvailable() != null && patientReminder.getSubscriptionAvailable() == 1);
|
|
|
+ reminderResponse.setBloodPressureEnabled(patientReminder.getBloodPressureEnabled() != null && patientReminder.getBloodPressureEnabled() == 1);
|
|
|
+ reminderResponse.setBloodSugarEnabled(patientReminder.getBloodSugarEnabled() != null && patientReminder.getBloodSugarEnabled() == 1);
|
|
|
+ reminderResponse.setHeartRateEnabled(patientReminder.getHeartRateEnabled() != null && patientReminder.getHeartRateEnabled() == 1);
|
|
|
+ reminderResponse.setMedicationEnabled(patientReminder.getMedicationEnabled() != null && patientReminder.getMedicationEnabled() == 1);
|
|
|
+ // 时间点字段使用 JsonUtils 解析为 List<String>
|
|
|
+ reminderResponse.setBloodPressureTimes(JsonUtils.fromJson(patientReminder.getBloodPressureTimes(), new TypeReference<List<String>>() {}));
|
|
|
+ reminderResponse.setBloodSugarTimes(JsonUtils.fromJson(patientReminder.getBloodSugarTimes(), new TypeReference<List<String>>() {}));
|
|
|
+ reminderResponse.setHeartRateTimes(JsonUtils.fromJson(patientReminder.getHeartRateTimes(), new TypeReference<List<String>>() {}));
|
|
|
response.setReminder(reminderResponse);
|
|
|
}
|
|
|
|
|
|
return response;
|
|
|
}
|
|
|
|
|
|
+注:若患者尚未设置提醒,`getReminderOverview` 将返回成功响应,但 `data.reminder` 为 `null`。调用方应对这种情况做兼容处理(例如在前端显示 "尚未设置提醒" 的提示)。
|
|
|
+
|
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
- public void savePatientReminder(CreatePatientReminderRequest request) {
|
|
|
+ public void savePatientReminder(PatientReminderRequest request) {
|
|
|
Long userId = SecurityUtils.getCurrentUserId();
|
|
|
|
|
|
// 检查是否已存在记录
|
|
|
@@ -387,52 +409,53 @@ public class PatientReminderServiceImpl implements PatientReminderService {
|
|
|
// 创建患者提醒设置
|
|
|
PatientReminder patientReminder = new PatientReminder();
|
|
|
patientReminder.setPatientUserId(userId);
|
|
|
- patientReminder.setNotificationEnabled(request.getNotificationEnabled() != null ? request.getNotificationEnabled() : true);
|
|
|
- patientReminder.setSubscriptionAvailable(request.getSubscriptionAvailable() != null ? request.getSubscriptionAvailable() : true);
|
|
|
- patientReminder.setBloodPressureEnabled(request.getBloodPressureEnabled() != null ? request.getBloodPressureEnabled() : true);
|
|
|
- patientReminder.setBloodPressureTimes(JSON.toJSONString(request.getBloodPressureTimes()));
|
|
|
- patientReminder.setBloodSugarEnabled(request.getBloodSugarEnabled() != null ? request.getBloodSugarEnabled() : false);
|
|
|
- patientReminder.setBloodSugarTimes(JSON.toJSONString(request.getBloodSugarTimes()));
|
|
|
- patientReminder.setHeartRateEnabled(request.getHeartRateEnabled() != null ? request.getHeartRateEnabled() : true);
|
|
|
- patientReminder.setHeartRateTimes(JSON.toJSONString(request.getHeartRateTimes()));
|
|
|
- patientReminder.setMedicationEnabled(request.getMedicationEnabled() != null ? request.getMedicationEnabled() : true);
|
|
|
+ // 设置默认值与类型转换(Boolean -> Byte),默认值与代码中一致
|
|
|
+ patientReminder.setNotificationEnabled(request.getNotificationEnabled() != null ? (request.getNotificationEnabled() ? (byte)1 : (byte)0) : (byte)1);
|
|
|
+ patientReminder.setSubscriptionAvailable(request.getSubscriptionAvailable() != null ? (request.getSubscriptionAvailable() ? (byte)1 : (byte)0) : (byte)1);
|
|
|
+ patientReminder.setBloodPressureEnabled(request.getBloodPressureEnabled() != null ? (request.getBloodPressureEnabled() ? (byte)1 : (byte)0) : (byte)1);
|
|
|
+ patientReminder.setBloodPressureTimes(JsonUtils.toJson(request.getBloodPressureTimes()));
|
|
|
+ patientReminder.setBloodSugarEnabled(request.getBloodSugarEnabled() != null ? (request.getBloodSugarEnabled() ? (byte)1 : (byte)0) : (byte)0);
|
|
|
+ patientReminder.setBloodSugarTimes(JsonUtils.toJson(request.getBloodSugarTimes()));
|
|
|
+ patientReminder.setHeartRateEnabled(request.getHeartRateEnabled() != null ? (request.getHeartRateEnabled() ? (byte)1 : (byte)0) : (byte)1);
|
|
|
+ patientReminder.setHeartRateTimes(JsonUtils.toJson(request.getHeartRateTimes()));
|
|
|
+ patientReminder.setMedicationEnabled(request.getMedicationEnabled() != null ? (request.getMedicationEnabled() ? (byte)1 : (byte)0) : (byte)1);
|
|
|
patientReminderMapper.insert(patientReminder);
|
|
|
} else {
|
|
|
// 更新提醒设置
|
|
|
if (request.getNotificationEnabled() != null) {
|
|
|
- existing.setNotificationEnabled(request.getNotificationEnabled());
|
|
|
+ existing.setNotificationEnabled(request.getNotificationEnabled() ? (byte)1 : (byte)0);
|
|
|
}
|
|
|
|
|
|
if (request.getSubscriptionAvailable() != null) {
|
|
|
- existing.setSubscriptionAvailable(request.getSubscriptionAvailable());
|
|
|
+ existing.setSubscriptionAvailable(request.getSubscriptionAvailable() ? (byte)1 : (byte)0);
|
|
|
}
|
|
|
|
|
|
if (request.getBloodPressureEnabled() != null) {
|
|
|
- existing.setBloodPressureEnabled(request.getBloodPressureEnabled());
|
|
|
+ existing.setBloodPressureEnabled(request.getBloodPressureEnabled() ? (byte)1 : (byte)0);
|
|
|
}
|
|
|
|
|
|
if (request.getBloodPressureTimes() != null) {
|
|
|
- existing.setBloodPressureTimes(JSON.toJSONString(request.getBloodPressureTimes()));
|
|
|
+ existing.setBloodPressureTimes(JsonUtils.toJson(request.getBloodPressureTimes()));
|
|
|
}
|
|
|
|
|
|
if (request.getBloodSugarEnabled() != null) {
|
|
|
- existing.setBloodSugarEnabled(request.getBloodSugarEnabled());
|
|
|
+ existing.setBloodSugarEnabled(request.getBloodSugarEnabled() ? (byte)1 : (byte)0);
|
|
|
}
|
|
|
|
|
|
if (request.getBloodSugarTimes() != null) {
|
|
|
- existing.setBloodSugarTimes(JSON.toJSONString(request.getBloodSugarTimes()));
|
|
|
+ existing.setBloodSugarTimes(JsonUtils.toJson(request.getBloodSugarTimes()));
|
|
|
}
|
|
|
|
|
|
if (request.getHeartRateEnabled() != null) {
|
|
|
- existing.setHeartRateEnabled(request.getHeartRateEnabled());
|
|
|
+ existing.setHeartRateEnabled(request.getHeartRateEnabled() ? (byte)1 : (byte)0);
|
|
|
}
|
|
|
|
|
|
if (request.getHeartRateTimes() != null) {
|
|
|
- existing.setHeartRateTimes(JSON.toJSONString(request.getHeartRateTimes()));
|
|
|
+ existing.setHeartRateTimes(JsonUtils.toJson(request.getHeartRateTimes()));
|
|
|
}
|
|
|
|
|
|
if (request.getMedicationEnabled() != null) {
|
|
|
- existing.setMedicationEnabled(request.getMedicationEnabled());
|
|
|
+ existing.setMedicationEnabled(request.getMedicationEnabled() ? (byte)1 : (byte)0);
|
|
|
}
|
|
|
|
|
|
patientReminderMapper.updateById(existing);
|
|
|
@@ -481,7 +504,7 @@ import org.springframework.http.MediaType;
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
import work.baiyun.chronicdiseaseapp.common.R;
|
|
|
import work.baiyun.chronicdiseaseapp.model.vo.PatientReminderOverviewResponse;
|
|
|
-import work.baiyun.chronicdiseaseapp.model.vo.CreatePatientReminderRequest;
|
|
|
+import work.baiyun.chronicdiseaseapp.model.vo.PatientReminderRequest;
|
|
|
import work.baiyun.chronicdiseaseapp.service.PatientReminderService;
|
|
|
import work.baiyun.chronicdiseaseapp.enums.ErrorCode;
|
|
|
import org.slf4j.Logger;
|
|
|
@@ -527,7 +550,7 @@ public class PatientReminderController {
|
|
|
schema = @Schema(implementation = Void.class)))
|
|
|
})
|
|
|
@PostMapping(path = "/save", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
|
|
- public R<?> savePatientReminder(@RequestBody CreatePatientReminderRequest req) {
|
|
|
+ public R<?> savePatientReminder(@RequestBody PatientReminderRequest req) {
|
|
|
try {
|
|
|
patientReminderService.savePatientReminder(req);
|
|
|
return R.success(200, "患者提醒设置保存成功");
|
|
|
@@ -561,10 +584,10 @@ public class PatientReminderController {
|
|
|
|
|
|
## 8. 错误码补充
|
|
|
|
|
|
-在 ErrorCode 枚举中可能需要添加以下错误码:
|
|
|
+当前实现使用 `ErrorCode.DATA_NOT_FOUND`(找不到记录)和 `ErrorCode.DATA_ACCESS_DENIED`(无权访问)来返回对应错误;如果你希望更精细的错误编码(便于前端识别或自动化监控),可以添加如下错误码:
|
|
|
|
|
|
```java
|
|
|
-// 在 ErrorCode.java 中添加
|
|
|
+// 在 ErrorCode.java 中添加(可选)
|
|
|
PATIENT_REMINDER_NOT_FOUND(7000, "患者提醒记录不存在"),
|
|
|
PATIENT_REMINDER_ACCESS_DENIED(7001, "无权访问患者提醒记录");
|
|
|
```
|
|
|
@@ -617,6 +640,8 @@ POST /patient-reminder/save
|
|
|
"heartRateTimes": ["18:00"],
|
|
|
"medicationEnabled": true
|
|
|
}
|
|
|
+
|
|
|
+注意:当 `notificationEnabled` 为 false 时,服务端会把 `subscriptionAvailable` 自动设置为 false;如果调用方同时传入 `subscriptionAvailable=true`,保存后仍会被重置为 false(以保证一致性)。
|
|
|
```
|
|
|
|
|
|
### 9.3 删除患者提醒设置
|