fix(scheduling): enforce one active intervention per current vehicle
Business rule: a running vehicle can hold AT MOST ONE active (sent|executed) intervention. Switching to a different candidate requires cancelling the prior one first. - Server: insertNotification dedup key changes from (suggestion_id, candidate_plate) to just suggestion_id; 409 response includes the blocking candidate plate - Detail modal: shows a banner naming the locked candidate; non-active candidates render a disabled "该车已有其他干预,请先解除" hint instead of the action button - Batch: pickBestCandidate returns null for any suggestion already holding an active intervention — the whole suggestion is excluded Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -147,10 +147,13 @@ function SkeletonPage() {
|
||||
}
|
||||
|
||||
function pickBestCandidate(s: SchedulingSuggestion): CandidateVehicle | null {
|
||||
// Prefer a candidate that can qualify and isn't already notified
|
||||
const available = s.candidates.filter(c => !c.notificationStatus || c.notificationStatus === 'cancelled');
|
||||
if (available.length === 0) return null;
|
||||
return available.find(c => c.canQualifyAfterSwap) ?? available[0];
|
||||
// Business rule: at most one active intervention per suggestion. If ANY
|
||||
// candidate is already intervened, skip the whole suggestion in batch flow.
|
||||
const hasActive = s.candidates.some(
|
||||
c => c.notificationStatus === 'sent' || c.notificationStatus === 'executed',
|
||||
);
|
||||
if (hasActive) return null;
|
||||
return s.candidates.find(c => c.canQualifyAfterSwap) ?? s.candidates[0] ?? null;
|
||||
}
|
||||
|
||||
export default function SchedulingModule() {
|
||||
|
||||
Reference in New Issue
Block a user