refactor(scheduling): shared types, structured reason, cross-region candidates

- Extract shared types to src/shared/scheduling/types.ts (client/server both re-export)
- Convert SchedulingSuggestion.reason from string to structured { lines, conclusion }
- Remove hard region filter; algorithm keeps cross-region candidates with isSameRegion flag
- SuggestionDetail renders same-region vs cross-region sections with a divider
- Close detail modal when selected suggestion no longer exists in data
- Unify estimatedGain definition (strict canQualifyAfterSwap) between algorithm and API layers

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-16 23:36:38 +08:00
parent 335282a2c3
commit 31716c6547
6 changed files with 250 additions and 240 deletions

View File

@@ -161,6 +161,13 @@ export default function SchedulingModule() {
useEffect(() => { loadData(); }, [loadData]);
const handleNotifySuccess = useCallback(() => { loadData(); }, [loadData]);
// Close detail modal if selected suggestion is filtered out or no longer exists
useEffect(() => {
if (!selectedSuggestion || !data) return;
const stillExists = data.suggestions.some(s => s.id === selectedSuggestion.id);
if (!stillExists) setSelectedSuggestion(null);
}, [data, selectedSuggestion]);
const filterOptions = useMemo(() => {
if (!data) return { regions: [], vehicleTypes: [], customers: [], departments: [], managers: [] };
const r = new Set<string>(), t = new Set<string>(), c = new Set<string>(), d = new Set<string>(), m = new Set<string>();