fix: prevent duplicate consultations with db unique constraint, frontend init once guard, chat history preserved
This commit is contained in:
@@ -41,7 +41,19 @@ public class ConsultationService(AppDbContext db)
|
|||||||
Subject = subject,
|
Subject = subject,
|
||||||
};
|
};
|
||||||
db.Consultations.Add(consultation);
|
db.Consultations.Add(consultation);
|
||||||
await db.SaveChangesAsync();
|
try
|
||||||
|
{
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
catch (DbUpdateException)
|
||||||
|
{
|
||||||
|
// Race condition: another request created one between our check and save
|
||||||
|
// The unique index on (PatientId, DoctorId) where Status='active' caught it
|
||||||
|
db.ChangeTracker.Clear();
|
||||||
|
var retry = await db.Consultations
|
||||||
|
.FirstOrDefaultAsync(c => c.PatientId == patientId && c.DoctorId == doctorId && c.Status == "active");
|
||||||
|
return retry!;
|
||||||
|
}
|
||||||
return consultation;
|
return consultation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export function ChatPage() {
|
|||||||
const [text, setText] = useState('');
|
const [text, setText] = useState('');
|
||||||
const [sending, setSending] = useState(false);
|
const [sending, setSending] = useState(false);
|
||||||
const bottomRef = useRef<HTMLDivElement>(null);
|
const bottomRef = useRef<HTMLDivElement>(null);
|
||||||
|
const initRef = useRef(false);
|
||||||
|
|
||||||
const loadMessages = useCallback((cid: string) => {
|
const loadMessages = useCallback((cid: string) => {
|
||||||
api.get<ConsultationMessage[]>(`/api/consultations/${cid}/messages`)
|
api.get<ConsultationMessage[]>(`/api/consultations/${cid}/messages`)
|
||||||
@@ -20,14 +21,30 @@ export function ChatPage() {
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Init once - prevent Strict Mode double-fire
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (initRef.current) return;
|
||||||
|
initRef.current = true;
|
||||||
|
|
||||||
consultationService.getDoctors().then((docs) => {
|
consultationService.getDoctors().then((docs) => {
|
||||||
if (docs.length > 0) {
|
if (docs.length > 0) {
|
||||||
const doc = docs[0];
|
const doc = docs[0];
|
||||||
setDoctor(doc);
|
setDoctor(doc);
|
||||||
consultationService.startConsultation(doc.id, '在线咨询').then((c) => {
|
// Find existing active consultation first
|
||||||
setConsultation(c);
|
api.get<Consultation[]>('/api/consultations').then((res) => {
|
||||||
loadMessages(c.id);
|
const existing = (res.data as Record<string, unknown>[]).find(
|
||||||
|
(c) => c.doctorId === doc.id && c.status === 'active'
|
||||||
|
);
|
||||||
|
if (existing) {
|
||||||
|
setConsultation(existing as unknown as Consultation);
|
||||||
|
loadMessages((existing as Record<string, string>).id);
|
||||||
|
} else {
|
||||||
|
// Create new only if none exists
|
||||||
|
consultationService.startConsultation(doc.id, '在线咨询').then((c) => {
|
||||||
|
setConsultation(c);
|
||||||
|
loadMessages(c.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user