diff --git a/backend/.env.example b/backend/.env.example deleted file mode 100644 index 762447b..0000000 --- a/backend/.env.example +++ /dev/null @@ -1,15 +0,0 @@ -# PostgreSQL -ConnectionStrings__Default=Host=localhost;Port=5432;Database=health_manager;Username=postgres;Password=your_password - -# JWT -Jwt__Secret=your-jwt-secret-change-me -Jwt__Issuer=HealthManager -Jwt__Audience=HealthManagerApp - -# Redis (reserved) -Redis__Connection=localhost:6379 - -# MinIO (reserved) -MinIO__Endpoint=localhost:9000 -MinIO__AccessKey=minioadmin -MinIO__SecretKey=minioadmin diff --git a/backend/src/HealthManager.WebApi/Controllers/AuthController.cs b/backend/src/HealthManager.WebApi/Controllers/AuthController.cs index bb3ef7b..2160190 100644 --- a/backend/src/HealthManager.WebApi/Controllers/AuthController.cs +++ b/backend/src/HealthManager.WebApi/Controllers/AuthController.cs @@ -5,6 +5,7 @@ using HealthManager.Application.Services; using HealthManager.Domain.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; namespace HealthManager.WebApi.Controllers; diff --git a/backend/src/HealthManager.WebApi/Controllers/MedicationController.cs b/backend/src/HealthManager.WebApi/Controllers/MedicationController.cs index a926e39..cd51041 100644 --- a/backend/src/HealthManager.WebApi/Controllers/MedicationController.cs +++ b/backend/src/HealthManager.WebApi/Controllers/MedicationController.cs @@ -71,7 +71,6 @@ public class MedicationController(MedicationService medicationService) : Control var rate = await medicationService.GetAdherenceRateAsync(id); return Ok(new { medicationId = id, rate }); } -} [HttpPut("{id:guid}")] public async Task UpdateMedication(Guid id, [FromBody] MedicationUpdateRequest request) diff --git a/backend/src/HealthManager.WebApi/Program.cs b/backend/src/HealthManager.WebApi/Program.cs index a10573f..809c627 100644 --- a/backend/src/HealthManager.WebApi/Program.cs +++ b/backend/src/HealthManager.WebApi/Program.cs @@ -9,24 +9,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Swashbuckle.AspNetCore.SwaggerGen; -// Load .env file into environment variables -var envPath = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "..", ".env"); -if (File.Exists(envPath)) -{ - foreach (var line in File.ReadAllLines(envPath)) - { - var trimmed = line.Trim(); - if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith('#')) continue; - var eq = trimmed.IndexOf('='); - if (eq > 0) - { - var key = trimmed[..eq].Trim(); - var value = trimmed[(eq + 1)..].Trim(); - Environment.SetEnvironmentVariable(key, value); - } - } -} - var builder = WebApplication.CreateBuilder(args); // Database diff --git a/backend/src/HealthManager.WebApi/appsettings.json b/backend/src/HealthManager.WebApi/appsettings.json index ab6f4c3..8118304 100644 --- a/backend/src/HealthManager.WebApi/appsettings.json +++ b/backend/src/HealthManager.WebApi/appsettings.json @@ -7,19 +7,19 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "Default": "" + "Default": "Host=localhost;Port=5432;Database=health_manager;Username=postgres;Password=postgres123" }, "Jwt": { - "Secret": "", + "Secret": "health-manager-jwt-secret-key-2026-super-secure-long-enough!", "Issuer": "HealthManager", "Audience": "HealthManagerApp" }, "Redis": { - "Connection": "" + "Connection": "localhost:6379" }, "MinIO": { - "Endpoint": "", - "AccessKey": "", - "SecretKey": "" + "Endpoint": "localhost:9000", + "AccessKey": "minioadmin", + "SecretKey": "minioadmin" } } diff --git a/frontend-doctor/src/pages/consultations/ChatPage.tsx b/frontend-doctor/src/pages/consultations/ChatPage.tsx index f4074bd..fe4d035 100644 --- a/frontend-doctor/src/pages/consultations/ChatPage.tsx +++ b/frontend-doctor/src/pages/consultations/ChatPage.tsx @@ -25,6 +25,7 @@ export function ChatPage() { const bottomRef = useRef(null); const connRef = useRef(null); + // Load initial messages via HTTP useEffect(() => { if (!id) return; api.get(`/api/consultations/${id}/messages`) @@ -32,11 +33,12 @@ export function ChatPage() { .catch(() => {}); }, [id]); + // Set up SignalR connection useEffect(() => { if (!id) return; const conn = new HubConnectionBuilder() - .withUrl(`${import.meta.env.VITE_API_URL}/hubs/chat`, { + .withUrl('http://localhost:5000/hubs/chat', { accessTokenFactory: () => getToken(), }) .withAutomaticReconnect() @@ -44,6 +46,7 @@ export function ChatPage() { conn.on('ReceiveMessage', (msg: Message) => { setMessages((prev) => { + // Dedup — guard against reconnection replay if (prev.some((m) => m.id === msg.id)) return prev; return [...prev, msg]; }); @@ -70,6 +73,7 @@ export function ChatPage() { }; }, [id]); + // Auto-scroll on new messages useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); @@ -85,37 +89,31 @@ export function ChatPage() { return (
-
+
在线问诊
-
+
{messages.map((msg) => (
{msg.content}
{msg.createdAt?.split('T')[1]?.slice(0, 5)}
@@ -125,23 +123,14 @@ export function ChatPage() {
-
+
setInput(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSend()} placeholder="输入回复..." - style={{ - flex: 1, padding: '11px 16px', border: '1.5px solid #E1E5ED', borderRadius: 24, - fontSize: 14, outline: 'none', - }} - onFocus={(e) => e.currentTarget.style.borderColor = '#4F6EF7'} - onBlur={(e) => e.currentTarget.style.borderColor = '#E1E5ED'} /> + style={{ flex: 1, padding: '10px 14px', border: '1px solid #ddd', borderRadius: 20, fontSize: 14 }} /> diff --git a/frontend-doctor/src/pages/reports/ReportDetailPage.tsx b/frontend-doctor/src/pages/reports/ReportDetailPage.tsx index 93ac094..21c71e4 100644 --- a/frontend-doctor/src/pages/reports/ReportDetailPage.tsx +++ b/frontend-doctor/src/pages/reports/ReportDetailPage.tsx @@ -7,7 +7,7 @@ interface RawReport { imageUrls: string[]; status: string; riskLevel?: string; summary?: string; suggestions?: string; patientName?: string; doctorName?: string; - uploadedAt: string; completedAt?: string; + createdAt: string; completedAt?: string; items?: RawItem[]; } @@ -56,54 +56,50 @@ export function ReportDetailPage() { finally { setSubmitting(false); } }; - if (!report) return
加载中...
; + if (!report) return
加载中...
; const isCompleted = report.status === 'completed'; const riskMap: Record = { - normal: { text: '正常', color: '#20C997' }, - attention: { text: '关注', color: '#F59E0B' }, - abnormal: { text: '异常', color: '#EF4444' }, - }; - - const inputStyle: React.CSSProperties = { - width: '100%', padding: '10px 14px', border: '1.5px solid #E1E5ED', - borderRadius: 10, fontSize: 13, outline: 'none', boxSizing: 'border-box', fontFamily: 'inherit', + normal: { text: '正常', color: '#2e7d32' }, + attention: { text: '关注', color: '#f57c00' }, + abnormal: { text: '异常', color: '#c62828' }, }; return ( -
- ← 返回报告列表 +
+ ← 返回报告列表 -
+
-

{report.title}

-
+

{report.title}

+
患者:{report.patientName || '未知'}  |  分类:{categoryMap[report.category] || report.category}  |  - 日期:{report.uploadedAt?.split('T')[0]} + 日期:{report.createdAt?.split('T')[0]}
{isCompleted ? '已完成' : '待审核'}
+ {/* 图片 */} {report.imageUrls && report.imageUrls.length > 0 && ( -
-

上传图片({report.imageUrls.length}张)

+
+

上传图片({report.imageUrls.length}张)

{report.imageUrls.map((url, i) => (
setLightbox(url)} style={{ - width: 120, height: 120, borderRadius: 12, overflow: 'hidden', - cursor: 'pointer', border: '2px solid #F0F2F5', background: '#F9FAFC', + width: 120, height: 120, borderRadius: 8, overflow: 'hidden', + cursor: 'pointer', border: '2px solid #eee', background: '#f5f5f5', display: 'flex', alignItems: 'center', justifyContent: 'center', }}> - {`图片${i}`} { (e.target as HTMLImageElement).style.display = 'none'; }} />
@@ -112,35 +108,37 @@ export function ReportDetailPage() {
)} + {/* 灯箱 */} {lightbox && (
setLightbox(null)} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.85)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 999, cursor: 'pointer', }}> - 预览 + 预览
)} + {/* 已完成解读 */} {isCompleted && ( -
-

解读结果

-
-

风险等级: +

+

解读结果

+
+

风险等级: {riskMap[report.riskLevel || '']?.text || report.riskLevel || '-'}

-

总结:{report.summary || '-'}

- {report.suggestions &&

建议:{report.suggestions}

} +

总结:{report.summary || '-'}

+ {report.suggestions &&

建议:{report.suggestions}

}
{report.items && report.items.length > 0 && ( - +
- - - - + + + + {report.items.map((item) => ( @@ -148,7 +146,7 @@ export function ReportDetailPage() { - @@ -159,66 +157,68 @@ export function ReportDetailPage() { )} + {/* 解读表单 */} {!isCompleted && ( -
-

医生解读

+
+

医生解读

-
- +
+
检查项目结果参考范围是否异常检查项目结果参考范围是否异常
{item.itemName} {item.resultValue} {item.unit || ''} {item.referenceRange || '-'} + {item.isAbnormal ? '是' : '否'}