feat: medication reminders, follow-up/visit separation, health record page

Backend:
- MedicationService: today-summary with missed detection (local time)
- FollowUpService: doctor-initiated follow-ups filter, AddAsync supports Notes
- FollowUpController: type query param (followup/recheck)
- MedicationController: today-summary endpoint
- Auth: UpdateProfileRequest→class, StentDate/StentType, soft-delete fix

Patient frontend:
- HomePage: date display, medication reminder cards with missed status
- MedicationListPage: beautified with delete button, slot preview
- MedicationDetailPage: redesigned with progress bars, new CSS
- ProfilePage: beautified menu icons, health record link
- HealthRecordPage: new page with indicators, history, meds, reports
- ServicesHub: added doctor-visit card
- VisitListPage: doctor-initiated follow-ups view
- EditProfilePage: removed height/weight, added stent fields
- Fixed getProfile field mappings (nickname, height, weight, stent)

Doctor frontend:
- Layout: added 随访管理 sidebar item with SVG icon
- FollowUpListPage: recheck-only filter, complete/delete buttons, collapsed completed
- VisitListPage/EditPage: doctor follow-up management
- PatientListPage: added stentType column
- Dashboard: fixed pending reports endpoint
- ReportListPage/DetailPage: fixed uploadedAt field
- ChatPage: SignalR real-time, dynamic hostname
This commit is contained in:
MingNian
2026-05-25 14:48:05 +08:00
parent db443b258e
commit 39ab6062b5
33 changed files with 1657 additions and 238 deletions

View File

@@ -136,6 +136,8 @@ public class AuthController(
if (request.HeightCm.HasValue) user.HeightCm = request.HeightCm;
if (request.WeightKg.HasValue) user.WeightKg = request.WeightKg;
if (request.MedicalHistory != null) user.MedicalHistory = request.MedicalHistory;
if (request.StentDate.HasValue) user.StentDate = request.StentDate;
if (request.StentType != null) user.StentType = request.StentType;
if (request.Department != null) user.Department = request.Department;
if (request.Title != null) user.Title = request.Title;
if (request.Introduction != null) user.Introduction = request.Introduction;

View File

@@ -14,11 +14,22 @@ public class FollowUpController(FollowUpService followUpService) : ControllerBas
private string Role => User.FindFirstValue(ClaimTypes.Role)!;
[HttpGet]
public async Task<IActionResult> GetFollowUps()
public async Task<IActionResult> GetFollowUps([FromQuery] string? type)
{
var followUps = Role == "doctor"
? await followUpService.GetDoctorFollowUpsAsync(UserId)
: await followUpService.GetPatientFollowUpsAsync(UserId);
List<HealthManager.Domain.Entities.FollowUp> followUps;
if (Role == "doctor" && type == "followup")
followUps = await followUpService.GetDoctorInitiatedFollowUpsAsync(UserId);
else if (Role == "doctor")
followUps = await followUpService.GetDoctorFollowUpsAsync(UserId);
else
{
followUps = await followUpService.GetPatientFollowUpsAsync(UserId);
if (type == "followup")
followUps = followUps.Where(f => f.DoctorId != null).ToList();
else if (type == "recheck")
followUps = followUps.Where(f => f.DoctorId == null).ToList();
}
return Ok(followUps.Select(f => new
{

View File

@@ -13,6 +13,13 @@ public class MedicationController(MedicationService medicationService) : Control
private Guid UserId => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
private string Role => User.FindFirstValue(ClaimTypes.Role)!;
[HttpGet("today-summary")]
public async Task<IActionResult> GetTodaySummary()
{
var summary = await medicationService.GetTodaySummaryAsync(UserId);
return Ok(summary);
}
[HttpGet]
public async Task<IActionResult> GetMedications()
{