feat(train-scheduling): implement container movement between wagons

- Added functionality to move containers between wagons in the train scheduling system.
- Introduced  API endpoint and service method to handle container movement.
- Updated  component to support drag-and-drop for rearranging containers.
- Enhanced  to allow moving containers to other wagons via a context menu.
- Implemented UI feedback for container movement actions, including loading states and success/error notifications.
- Updated relevant types and constants to accommodate new container movement logic.
- Added tests for the rule engine to ensure proper handling of hazardous bookings.
This commit is contained in:
Marshal
2026-07-21 23:02:06 +00:00
parent 00a81fda15
commit 835c9e111c
35 changed files with 1896 additions and 154 deletions

View File

@@ -146,10 +146,8 @@ export class IntercityService {
remaining: capacity?.budget.maxRemaining() ?? null,
candidates: waiting.map((booking) => {
const need = capacity?.needFor(booking) ?? null;
// legForYards, not legOf: on a built train the budget is a single
// whole-route edge (see intercityCapacity), so a mid-corridor booking
// must draw from that one pool via the whole-route fallback. On a
// locomotive-derived schedule it still resolves to the booking's own leg.
// legForYards: the booking draws only from ITS OWN leg's edges, with a
// whole-route fallback when its yards aren't on the budget's stop list.
const leg = capacity?.budget.legForYards(
booking.originYardId,
booking.destinationYardId,
@@ -215,11 +213,8 @@ export class IntercityService {
continue;
}
const need = capacity.needFor(booking);
// legForYards, not legOf: a built train's budget is a single whole-route
// pool (mid-corridor wagons are committed for the whole trip and never
// reloaded), so the booking draws from that pool via the whole-route
// fallback; a locomotive-derived schedule still gets the booking's own
// leg, so it can still board a train that is full only on other legs.
// legForYards: charge only the edges this booking rides, so it can still
// board a train that is full only on other legs.
const leg = budget.legForYards(booking.originYardId, booking.destinationYardId);
if (!budget.fits(need, leg)) {
rejected.push({