yard-management

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Yard Management

堆场管理

You are an expert in yard management and trailer logistics. Your goal is to help optimize yard operations, improve trailer visibility, reduce detention costs, and maximize dock door utilization through efficient yard management practices and technology.
您是yard management和拖车物流领域的专家。您的目标是通过高效的堆场管理实践与技术,帮助优化堆场作业、提升拖车可见性、降低滞留成本,并最大化码头门利用率。

Initial Assessment

初始评估

Before optimizing yard operations, understand:
  1. Facility Characteristics
    • Yard size and capacity? (trailer spots)
    • Number of dock doors?
    • Layout constraints? (space, access, turning radius)
    • Gate security and check-in process?
  2. Operational Volume
    • Daily inbound/outbound trailers?
    • Average dwell time per trailer?
    • Peak times and patterns?
    • Types of trailers? (dry van, reefer, flatbed)
  3. Current Challenges
    • Trailer visibility issues?
    • Long wait times at gate or dock?
    • High detention/demurrage costs?
    • Difficulty finding trailers in yard?
    • Congestion at doors?
  4. Resources
    • Number of yard jockeys?
    • Yard tractors available?
    • Technology in place? (YMS, GPS, RFID)
    • Staffing and shifts?

在优化堆场作业前,需了解以下信息:
  1. 设施特征
    • 堆场规模与容量?(拖车泊位数量)
    • 码头门数量?
    • 布局限制?(空间、通道、转弯半径)
    • 闸口安全与登记流程?
  2. 作业量
    • 每日进出拖车数量?
    • 每辆拖车的平均停留时间?
    • 高峰时段与规律?
    • 拖车类型?(干货厢式车、冷藏车、平板车)
  3. 当前挑战
    • 拖车可见性问题?
    • 闸口或码头等待时间过长?
    • 高额滞留/滞期费用?
    • 难以在堆场中找到拖车?
    • 码头门拥堵?
  4. 资源情况
    • yard jockey数量?
    • 可用堆场牵引车数量?
    • 现有技术?(YMS、GPS、RFID)
    • 人员配置与轮班情况?

Yard Management Framework

堆场管理框架

Core Functions of Yard Management

堆场管理核心功能

1. Gate Management
  • Check-in/check-out process
  • Carrier credential verification
  • BOL and documentation
  • Safety inspections
  • Appointment verification
2. Yard Planning & Layout
  • Trailer parking locations
  • Staging zones by priority
  • Dock door assignments
  • Traffic flow optimization
3. Trailer Movement
  • Yard jockey dispatch
  • Spotting trailers at doors
  • Repositioning for loading/unloading
  • Trailer pool management
4. Tracking & Visibility
  • Real-time trailer location
  • Load status (empty, loaded, in-process)
  • Dwell time monitoring
  • Exception management
5. Dock Scheduling
  • Appointment booking
  • Door assignment
  • Load/unload coordination
  • Carrier communication

1. 闸口管理
  • 登记/注销流程
  • 承运人资质验证
  • BOL与文件处理
  • 安全检查
  • 预约验证
2. 堆场规划与布局
  • 拖车停放位置
  • 按优先级划分的 staging zones
  • 码头门分配
  • 交通流向优化
3. 拖车调度
  • yard jockey调度
  • 拖车停靠码头门
  • 为装卸作业重新调度拖车
  • 拖车池管理
4. 跟踪与可见性
  • 实时拖车位置
  • 装载状态(空车、已装载、作业中)
  • 停留时间监控
  • 异常管理
5. 码头调度
  • 预约预订
  • 码头门分配
  • 装卸协调
  • 承运人沟通

Yard Layout Optimization

堆场布局优化

Yard Design Principles

堆场设计原则

python
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import distance

class YardLayoutOptimizer:
    """
    Optimize yard layout and trailer positioning

    Minimize jockey moves and door spotting time
    """

    def __init__(self, num_doors, yard_capacity, dock_positions):
        """
        Parameters:
        - num_doors: number of dock doors
        - yard_capacity: total trailer parking spots
        - dock_positions: list of (x, y) coordinates for each door
        """
        self.num_doors = num_doors
        self.yard_capacity = yard_capacity
        self.dock_positions = np.array(dock_positions)

    def design_staging_zones(self, zone_types=['inbound', 'outbound',
                                              'live', 'empty']):
        """
        Design staging zones based on trailer status

        Returns optimal zone assignments
        """

        # Allocate yard capacity by zone
        # Typical allocation:
        # - Inbound waiting: 30%
        # - Outbound ready: 25%
        # - Live loading/unloading: 20%
        # - Empty/drop trailers: 25%

        allocations = {
            'inbound': int(self.yard_capacity * 0.30),
            'outbound': int(self.yard_capacity * 0.25),
            'live': int(self.yard_capacity * 0.20),
            'empty': int(self.yard_capacity * 0.25)
        }

        # Position zones near relevant doors
        zones = {}

        # Inbound zone: Near inbound doors (first half)
        zones['inbound'] = {
            'capacity': allocations['inbound'],
            'preferred_doors': list(range(self.num_doors // 2)),
            'avg_distance_to_door': 50  # feet
        }

        # Outbound zone: Near outbound doors (second half)
        zones['outbound'] = {
            'capacity': allocations['outbound'],
            'preferred_doors': list(range(self.num_doors // 2, self.num_doors)),
            'avg_distance_to_door': 50
        }

        # Live zone: Immediately adjacent to doors
        zones['live'] = {
            'capacity': allocations['live'],
            'preferred_doors': list(range(self.num_doors)),
            'avg_distance_to_door': 20  # Closest
        }

        # Empty zone: Furthest from doors
        zones['empty'] = {
            'capacity': allocations['empty'],
            'preferred_doors': [],
            'avg_distance_to_door': 150  # Furthest
        }

        return zones

    def calculate_optimal_spot_locations(self, num_spots, zone_center,
                                        spacing=60):
        """
        Calculate grid of trailer parking spots

        Parameters:
        - num_spots: number of spots needed
        - zone_center: (x, y) center of zone
        - spacing: feet between trailers
        """

        # Create grid layout
        spots_per_row = 10  # Standard configuration
        num_rows = int(np.ceil(num_spots / spots_per_row))

        spots = []
        for row in range(num_rows):
            for col in range(spots_per_row):
                if len(spots) >= num_spots:
                    break

                x = zone_center[0] + (col * spacing)
                y = zone_center[1] + (row * spacing)

                spots.append({
                    'spot_id': f'S{len(spots)+1:03d}',
                    'position': (x, y),
                    'row': row,
                    'col': col
                })

        return spots

    def assign_trailer_to_spot(self, trailer_status, trailer_door_assignment,
                              available_spots):
        """
        Assign trailer to optimal parking spot

        Minimize distance to assigned door

        Parameters:
        - trailer_status: 'inbound', 'outbound', 'live', 'empty'
        - trailer_door_assignment: door number (if assigned)
        - available_spots: list of available spot dictionaries
        """

        # Filter spots by zone preference
        zone_spots = [
            spot for spot in available_spots
            if spot.get('zone') == trailer_status
        ]

        if not zone_spots:
            zone_spots = available_spots  # Use any available

        if not zone_spots:
            return None  # Yard full

        # If door assigned, find closest spot to that door
        if trailer_door_assignment is not None:
            door_position = self.dock_positions[trailer_door_assignment]

            # Calculate distances
            distances = [
                distance.euclidean(spot['position'], door_position)
                for spot in zone_spots
            ]

            # Select closest spot
            best_spot_idx = np.argmin(distances)
            assigned_spot = zone_spots[best_spot_idx]

        else:
            # No door assigned, use first available in zone
            assigned_spot = zone_spots[0]

        return assigned_spot

    def analyze_yard_utilization(self, occupied_spots, total_spots):
        """
        Calculate yard utilization metrics

        Returns utilization by zone and overall
        """

        utilization = {
            'total_spots': total_spots,
            'occupied_spots': len(occupied_spots),
            'utilization_pct': len(occupied_spots) / total_spots * 100,
            'available_spots': total_spots - len(occupied_spots)
        }

        # By zone
        zones = {}
        for spot in occupied_spots:
            zone = spot.get('zone', 'unknown')
            if zone not in zones:
                zones[zone] = 0
            zones[zone] += 1

        utilization['by_zone'] = zones

        return utilization
python
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import distance

class YardLayoutOptimizer:
    """
    Optimize yard layout and trailer positioning

    Minimize jockey moves and door spotting time
    """

    def __init__(self, num_doors, yard_capacity, dock_positions):
        """
        Parameters:
        - num_doors: number of dock doors
        - yard_capacity: total trailer parking spots
        - dock_positions: list of (x, y) coordinates for each door
        """
        self.num_doors = num_doors
        self.yard_capacity = yard_capacity
        self.dock_positions = np.array(dock_positions)

    def design_staging_zones(self, zone_types=['inbound', 'outbound',
                                              'live', 'empty']):
        """
        Design staging zones based on trailer status

        Returns optimal zone assignments
        """

        # Allocate yard capacity by zone
        # Typical allocation:
        # - Inbound waiting: 30%
        # - Outbound ready: 25%
        # - Live loading/unloading: 20%
        # - Empty/drop trailers: 25%

        allocations = {
            'inbound': int(self.yard_capacity * 0.30),
            'outbound': int(self.yard_capacity * 0.25),
            'live': int(self.yard_capacity * 0.20),
            'empty': int(self.yard_capacity * 0.25)
        }

        # Position zones near relevant doors
        zones = {}

        # Inbound zone: Near inbound doors (first half)
        zones['inbound'] = {
            'capacity': allocations['inbound'],
            'preferred_doors': list(range(self.num_doors // 2)),
            'avg_distance_to_door': 50  # feet
        }

        # Outbound zone: Near outbound doors (second half)
        zones['outbound'] = {
            'capacity': allocations['outbound'],
            'preferred_doors': list(range(self.num_doors // 2, self.num_doors)),
            'avg_distance_to_door': 50
        }

        # Live zone: Immediately adjacent to doors
        zones['live'] = {
            'capacity': allocations['live'],
            'preferred_doors': list(range(self.num_doors)),
            'avg_distance_to_door': 20  # Closest
        }

        # Empty zone: Furthest from doors
        zones['empty'] = {
            'capacity': allocations['empty'],
            'preferred_doors': [],
            'avg_distance_to_door': 150  # Furthest
        }

        return zones

    def calculate_optimal_spot_locations(self, num_spots, zone_center,
                                        spacing=60):
        """
        Calculate grid of trailer parking spots

        Parameters:
        - num_spots: number of spots needed
        - zone_center: (x, y) center of zone
        - spacing: feet between trailers
        """

        # Create grid layout
        spots_per_row = 10  # Standard configuration
        num_rows = int(np.ceil(num_spots / spots_per_row))

        spots = []
        for row in range(num_rows):
            for col in range(spots_per_row):
                if len(spots) >= num_spots:
                    break

                x = zone_center[0] + (col * spacing)
                y = zone_center[1] + (row * spacing)

                spots.append({
                    'spot_id': f'S{len(spots)+1:03d}',
                    'position': (x, y),
                    'row': row,
                    'col': col
                })

        return spots

    def assign_trailer_to_spot(self, trailer_status, trailer_door_assignment,
                              available_spots):
        """
        Assign trailer to optimal parking spot

        Minimize distance to assigned door

        Parameters:
        - trailer_status: 'inbound', 'outbound', 'live', 'empty'
        - trailer_door_assignment: door number (if assigned)
        - available_spots: list of available spot dictionaries
        """

        # Filter spots by zone preference
        zone_spots = [
            spot for spot in available_spots
            if spot.get('zone') == trailer_status
        ]

        if not zone_spots:
            zone_spots = available_spots  # Use any available

        if not zone_spots:
            return None  # Yard full

        # If door assigned, find closest spot to that door
        if trailer_door_assignment is not None:
            door_position = self.dock_positions[trailer_door_assignment]

            # Calculate distances
            distances = [
                distance.euclidean(spot['position'], door_position)
                for spot in zone_spots
            ]

            # Select closest spot
            best_spot_idx = np.argmin(distances)
            assigned_spot = zone_spots[best_spot_idx]

        else:
            # No door assigned, use first available in zone
            assigned_spot = zone_spots[0]

        return assigned_spot

    def analyze_yard_utilization(self, occupied_spots, total_spots):
        """
        Calculate yard utilization metrics

        Returns utilization by zone and overall
        """

        utilization = {
            'total_spots': total_spots,
            'occupied_spots': len(occupied_spots),
            'utilization_pct': len(occupied_spots) / total_spots * 100,
            'available_spots': total_spots - len(occupied_spots)
        }

        # By zone
        zones = {}
        for spot in occupied_spots:
            zone = spot.get('zone', 'unknown')
            if zone not in zones:
                zones[zone] = 0
            zones[zone] += 1

        utilization['by_zone'] = zones

        return utilization

Example usage

Example usage

optimizer = YardLayoutOptimizer( num_doors=40, yard_capacity=200, dock_positions=[(i*20, 0) for i in range(40)] # Doors in a line )
zones = optimizer.design_staging_zones() print("Staging Zones:") for zone_name, zone_info in zones.items(): print(f" {zone_name}: {zone_info['capacity']} spots, " f"avg distance {zone_info['avg_distance_to_door']} ft")

---
optimizer = YardLayoutOptimizer( num_doors=40, yard_capacity=200, dock_positions=[(i*20, 0) for i in range(40)] # Doors in a line )
zones = optimizer.design_staging_zones() print("Staging Zones:") for zone_name, zone_info in zones.items(): print(f" {zone_name}: {zone_info['capacity']} spots, " f"avg distance {zone_info['avg_distance_to_door']} ft")

---

Dock Door Scheduling

码头门调度

Appointment Scheduling System

预约调度系统

python
import pandas as pd
from datetime import datetime, timedelta

class DockSchedulingSystem:
    """
    Manage dock door appointments and scheduling

    Optimize door utilization and minimize wait times
    """

    def __init__(self, num_doors, hours_of_operation=(6, 22)):
        """
        Parameters:
        - num_doors: number of dock doors
        - hours_of_operation: (start_hour, end_hour) tuple
        """
        self.num_doors = num_doors
        self.start_hour = hours_of_operation[0]
        self.end_hour = hours_of_operation[1]
        self.schedule = {}

    def create_time_slots(self, date, slot_duration_hours=2):
        """
        Create available time slots for a date

        Returns list of time slots
        """

        slots = []
        current_time = datetime.combine(date, datetime.min.time()).replace(
            hour=self.start_hour
        )
        end_time = datetime.combine(date, datetime.min.time()).replace(
            hour=self.end_hour
        )

        while current_time < end_time:
            slot_end = current_time + timedelta(hours=slot_duration_hours)

            slots.append({
                'start_time': current_time,
                'end_time': slot_end,
                'available_doors': list(range(self.num_doors))
            })

            current_time = slot_end

        return slots

    def book_appointment(self, carrier, appointment_type, requested_time,
                        duration_hours=2, door_preference=None):
        """
        Book dock appointment

        Parameters:
        - carrier: carrier name
        - appointment_type: 'inbound' or 'outbound'
        - requested_time: datetime
        - duration_hours: expected duration
        - door_preference: specific door number (optional)
        """

        date = requested_time.date()

        # Get or create slots for date
        if date not in self.schedule:
            self.schedule[date] = self.create_time_slots(date)

        # Find matching time slot
        for slot in self.schedule[date]:
            if (slot['start_time'] <= requested_time <
                slot['end_time'] and
                len(slot['available_doors']) > 0):

                # Assign door
                if door_preference and door_preference in slot['available_doors']:
                    assigned_door = door_preference
                else:
                    assigned_door = slot['available_doors'][0]

                # Remove door from available
                slot['available_doors'].remove(assigned_door)

                appointment = {
                    'appointment_id': f"APT{len(self.schedule)*100 + 1}",
                    'carrier': carrier,
                    'type': appointment_type,
                    'scheduled_time': slot['start_time'],
                    'door': assigned_door,
                    'duration': duration_hours,
                    'status': 'scheduled'
                }

                return appointment

        # No available slot found
        return {
            'error': 'No available slot',
            'requested_time': requested_time,
            'suggestion': 'Try different time or date'
        }

    def check_availability(self, date, appointment_type=None):
        """
        Check door availability for a date

        Returns available slots
        """

        if date not in self.schedule:
            self.schedule[date] = self.create_time_slots(date)

        availability = []

        for slot in self.schedule[date]:
            if len(slot['available_doors']) > 0:
                availability.append({
                    'time_slot': f"{slot['start_time'].strftime('%H:%M')} - "
                                f"{slot['end_time'].strftime('%H:%M')}",
                    'available_doors': len(slot['available_doors']),
                    'door_numbers': slot['available_doors'][:5]  # Show first 5
                })

        return availability

    def calculate_utilization(self, date):
        """
        Calculate door utilization for a date

        Returns utilization percentage
        """

        if date not in self.schedule:
            return {'utilization': 0, 'message': 'No appointments scheduled'}

        total_door_slots = 0
        used_door_slots = 0

        for slot in self.schedule[date]:
            # Each slot has potential of all doors
            total_door_slots += self.num_doors

            # Count used doors (initially available - currently available)
            used_doors = self.num_doors - len(slot['available_doors'])
            used_door_slots += used_doors

        utilization = used_door_slots / total_door_slots * 100 if total_door_slots > 0 else 0

        return {
            'date': date,
            'utilization_pct': utilization,
            'total_door_slots': total_door_slots,
            'used_door_slots': used_door_slots,
            'target_utilization': 75  # Best practice target
        }

    def optimize_door_assignments(self, appointments):
        """
        Re-optimize door assignments to minimize moves

        Group similar appointment types on adjacent doors
        """

        # Separate by type
        inbound = [a for a in appointments if a['type'] == 'inbound']
        outbound = [a for a in appointments if a['type'] == 'outbound']

        # Assign inbound to first half of doors
        inbound_doors = list(range(self.num_doors // 2))
        outbound_doors = list(range(self.num_doors // 2, self.num_doors))

        # Reassign
        for idx, appt in enumerate(inbound):
            if idx < len(inbound_doors):
                appt['door'] = inbound_doors[idx]

        for idx, appt in enumerate(outbound):
            if idx < len(outbound_doors):
                appt['door'] = outbound_doors[idx]

        return appointments
python
import pandas as pd
from datetime import datetime, timedelta

class DockSchedulingSystem:
    """
    Manage dock door appointments and scheduling

    Optimize door utilization and minimize wait times
    """

    def __init__(self, num_doors, hours_of_operation=(6, 22)):
        """
        Parameters:
        - num_doors: number of dock doors
        - hours_of_operation: (start_hour, end_hour) tuple
        """
        self.num_doors = num_doors
        self.start_hour = hours_of_operation[0]
        self.end_hour = hours_of_operation[1]
        self.schedule = {}

    def create_time_slots(self, date, slot_duration_hours=2):
        """
        Create available time slots for a date

        Returns list of time slots
        """

        slots = []
        current_time = datetime.combine(date, datetime.min.time()).replace(
            hour=self.start_hour
        )
        end_time = datetime.combine(date, datetime.min.time()).replace(
            hour=self.end_hour
        )

        while current_time < end_time:
            slot_end = current_time + timedelta(hours=slot_duration_hours)

            slots.append({
                'start_time': current_time,
                'end_time': slot_end,
                'available_doors': list(range(self.num_doors))
            })

            current_time = slot_end

        return slots

    def book_appointment(self, carrier, appointment_type, requested_time,
                        duration_hours=2, door_preference=None):
        """
        Book dock appointment

        Parameters:
        - carrier: carrier name
        - appointment_type: 'inbound' or 'outbound'
        - requested_time: datetime
        - duration_hours: expected duration
        - door_preference: specific door number (optional)
        """

        date = requested_time.date()

        # Get or create slots for date
        if date not in self.schedule:
            self.schedule[date] = self.create_time_slots(date)

        # Find matching time slot
        for slot in self.schedule[date]:
            if (slot['start_time'] <= requested_time <
                slot['end_time'] and
                len(slot['available_doors']) > 0):

                # Assign door
                if door_preference and door_preference in slot['available_doors']:
                    assigned_door = door_preference
                else:
                    assigned_door = slot['available_doors'][0]

                # Remove door from available
                slot['available_doors'].remove(assigned_door)

                appointment = {
                    'appointment_id': f"APT{len(self.schedule)*100 + 1}",
                    'carrier': carrier,
                    'type': appointment_type,
                    'scheduled_time': slot['start_time'],
                    'door': assigned_door,
                    'duration': duration_hours,
                    'status': 'scheduled'
                }

                return appointment

        # No available slot found
        return {
            'error': 'No available slot',
            'requested_time': requested_time,
            'suggestion': 'Try different time or date'
        }

    def check_availability(self, date, appointment_type=None):
        """
        Check door availability for a date

        Returns available slots
        """

        if date not in self.schedule:
            self.schedule[date] = self.create_time_slots(date)

        availability = []

        for slot in self.schedule[date]:
            if len(slot['available_doors']) > 0:
                availability.append({
                    'time_slot': f"{slot['start_time'].strftime('%H:%M')} - "
                                f"{slot['end_time'].strftime('%H:%M')}",
                    'available_doors': len(slot['available_doors']),
                    'door_numbers': slot['available_doors'][:5]  # Show first 5
                })

        return availability

    def calculate_utilization(self, date):
        """
        Calculate door utilization for a date

        Returns utilization percentage
        """

        if date not in self.schedule:
            return {'utilization': 0, 'message': 'No appointments scheduled'}

        total_door_slots = 0
        used_door_slots = 0

        for slot in self.schedule[date]:
            # Each slot has potential of all doors
            total_door_slots += self.num_doors

            # Count used doors (initially available - currently available)
            used_doors = self.num_doors - len(slot['available_doors'])
            used_door_slots += used_doors

        utilization = used_door_slots / total_door_slots * 100 if total_door_slots > 0 else 0

        return {
            'date': date,
            'utilization_pct': utilization,
            'total_door_slots': total_door_slots,
            'used_door_slots': used_door_slots,
            'target_utilization': 75  # Best practice target
        }

    def optimize_door_assignments(self, appointments):
        """
        Re-optimize door assignments to minimize moves

        Group similar appointment types on adjacent doors
        """

        # Separate by type
        inbound = [a for a in appointments if a['type'] == 'inbound']
        outbound = [a for a in appointments if a['type'] == 'outbound']

        # Assign inbound to first half of doors
        inbound_doors = list(range(self.num_doors // 2))
        outbound_doors = list(range(self.num_doors // 2, self.num_doors))

        # Reassign
        for idx, appt in enumerate(inbound):
            if idx < len(inbound_doors):
                appt['door'] = inbound_doors[idx]

        for idx, appt in enumerate(outbound):
            if idx < len(outbound_doors):
                appt['door'] = outbound_doors[idx]

        return appointments

Example usage

Example usage

scheduler = DockSchedulingSystem(num_doors=40)
scheduler = DockSchedulingSystem(num_doors=40)

Book appointments

Book appointments

appt1 = scheduler.book_appointment( carrier='ABC Trucking', appointment_type='inbound', requested_time=datetime.now().replace(hour=8, minute=0) )
print(f"Appointment booked: Door {appt1.get('door')} at " f"{appt1.get('scheduled_time')}")
appt1 = scheduler.book_appointment( carrier='ABC Trucking', appointment_type='inbound', requested_time=datetime.now().replace(hour=8, minute=0) )
print(f"Appointment booked: Door {appt1.get('door')} at " f"{appt1.get('scheduled_time')}")

Check availability

Check availability

tomorrow = datetime.now().date() + timedelta(days=1) availability = scheduler.check_availability(tomorrow) print(f"\nAvailability for {tomorrow}:") for slot in availability[:3]: print(f" {slot['time_slot']}: {slot['available_doors']} doors available")

---
tomorrow = datetime.now().date() + timedelta(days=1) availability = scheduler.check_availability(tomorrow) print(f"\nAvailability for {tomorrow}:") for slot in availability[:3]: print(f" {slot['time_slot']}: {slot['available_doors']} doors available")

---

Trailer Tracking & Visibility

拖车跟踪与可见性

Yard Management System (YMS) Core Functions

堆场管理系统(YMS)核心功能

python
class YardManagementSystem:
    """
    Core yard management system functionality

    Track trailers, manage moves, monitor dwell time
    """

    def __init__(self):
        self.trailers = {}  # trailer_id -> trailer info
        self.yard_spots = {}  # spot_id -> trailer_id
        self.move_history = []
        self.alerts = []

    def check_in_trailer(self, trailer_id, carrier, seal_number,
                        trailer_type='dry_van', is_loaded=True):
        """
        Check in trailer at gate

        Creates trailer record in system
        """

        check_in_time = datetime.now()

        trailer_info = {
            'trailer_id': trailer_id,
            'carrier': carrier,
            'seal_number': seal_number,
            'trailer_type': trailer_type,
            'is_loaded': is_loaded,
            'status': 'in_yard',
            'check_in_time': check_in_time,
            'current_location': 'gate',
            'dock_door': None,
            'moves': 0
        }

        self.trailers[trailer_id] = trailer_info

        # Log move
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': check_in_time,
            'action': 'check_in',
            'location': 'gate'
        })

        return trailer_info

    def assign_yard_spot(self, trailer_id, spot_id):
        """
        Assign trailer to yard parking spot

        Parameters:
        - trailer_id: unique trailer identifier
        - spot_id: yard spot identifier
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        if spot_id in self.yard_spots and self.yard_spots[spot_id] is not None:
            return {'error': f'Spot {spot_id} already occupied'}

        # Update trailer location
        trailer = self.trailers[trailer_id]
        old_location = trailer['current_location']
        trailer['current_location'] = spot_id
        trailer['moves'] += 1

        # Update spot
        if old_location in self.yard_spots:
            self.yard_spots[old_location] = None  # Free old spot

        self.yard_spots[spot_id] = trailer_id

        # Log move
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'move_to_spot',
            'from': old_location,
            'to': spot_id
        })

        return {
            'trailer_id': trailer_id,
            'assigned_spot': spot_id,
            'moves': trailer['moves']
        }

    def spot_trailer_at_door(self, trailer_id, door_number):
        """
        Spot trailer at dock door for loading/unloading

        Parameters:
        - trailer_id: trailer to spot
        - door_number: dock door number
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        trailer = self.trailers[trailer_id]
        old_location = trailer['current_location']

        # Update trailer
        trailer['current_location'] = f'door_{door_number}'
        trailer['dock_door'] = door_number
        trailer['status'] = 'at_door'
        trailer['door_arrival_time'] = datetime.now()
        trailer['moves'] += 1

        # Free old spot if in yard
        if old_location in self.yard_spots:
            self.yard_spots[old_location] = None

        # Log move
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'spot_at_door',
            'door': door_number,
            'from': old_location
        })

        return {
            'trailer_id': trailer_id,
            'door': door_number,
            'spotted_time': trailer['door_arrival_time']
        }

    def complete_door_activity(self, trailer_id):
        """
        Complete loading/unloading at door

        Move trailer back to yard or check out
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        trailer = self.trailers[trailer_id]

        if trailer['status'] != 'at_door':
            return {'error': 'Trailer not at door'}

        # Calculate door dwell time
        door_dwell = (datetime.now() - trailer['door_arrival_time']).total_seconds() / 3600

        trailer['status'] = 'completed'
        trailer['door_departure_time'] = datetime.now()
        trailer['door_dwell_hours'] = door_dwell

        # Log
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'complete_door_activity',
            'door_dwell_hours': door_dwell
        })

        # Check for excessive door time (>2 hours)
        if door_dwell > 2:
            self.alerts.append({
                'alert_type': 'excessive_door_dwell',
                'trailer_id': trailer_id,
                'door_dwell_hours': door_dwell,
                'timestamp': datetime.now()
            })

        return {
            'trailer_id': trailer_id,
            'door_dwell_hours': door_dwell,
            'status': 'completed'
        }

    def check_out_trailer(self, trailer_id):
        """
        Check out trailer from facility

        Final step before trailer leaves
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        trailer = self.trailers[trailer_id]

        # Calculate total yard dwell
        total_dwell = (datetime.now() - trailer['check_in_time']).total_seconds() / 3600

        trailer['status'] = 'checked_out'
        trailer['check_out_time'] = datetime.now()
        trailer['total_yard_dwell_hours'] = total_dwell

        # Log
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'check_out',
            'total_dwell_hours': total_dwell
        })

        # Alert if excessive yard dwell (>24 hours)
        if total_dwell > 24:
            self.alerts.append({
                'alert_type': 'excessive_yard_dwell',
                'trailer_id': trailer_id,
                'total_dwell_hours': total_dwell,
                'timestamp': datetime.now()
            })

        return {
            'trailer_id': trailer_id,
            'total_yard_dwell_hours': total_dwell,
            'total_moves': trailer['moves']
        }

    def get_yard_status(self):
        """
        Get current yard status summary

        Returns counts by status
        """

        status_counts = {}
        for trailer in self.trailers.values():
            status = trailer['status']
            status_counts[status] = status_counts.get(status, 0) + 1

        total_trailers = len(self.trailers)
        occupied_spots = sum(1 for spot in self.yard_spots.values()
                           if spot is not None)

        return {
            'total_trailers_in_yard': total_trailers,
            'occupied_spots': occupied_spots,
            'by_status': status_counts,
            'active_alerts': len(self.alerts)
        }

    def find_trailer(self, trailer_id):
        """
        Locate trailer in yard

        Returns current location
        """

        if trailer_id not in self.trailers:
            return {'error': 'Trailer not found'}

        trailer = self.trailers[trailer_id]

        return {
            'trailer_id': trailer_id,
            'current_location': trailer['current_location'],
            'status': trailer['status'],
            'carrier': trailer['carrier'],
            'dwell_time_hours': (datetime.now() - trailer['check_in_time']).total_seconds() / 3600
        }

    def calculate_performance_metrics(self):
        """
        Calculate yard performance metrics

        Returns KPIs
        """

        if not self.trailers:
            return {'message': 'No data available'}

        # Average dwell time
        dwell_times = []
        for trailer in self.trailers.values():
            if 'total_yard_dwell_hours' in trailer:
                dwell_times.append(trailer['total_yard_dwell_hours'])

        avg_dwell = np.mean(dwell_times) if dwell_times else 0

        # Average moves per trailer
        moves = [t['moves'] for t in self.trailers.values()]
        avg_moves = np.mean(moves) if moves else 0

        # Door dwell times
        door_dwells = []
        for trailer in self.trailers.values():
            if 'door_dwell_hours' in trailer:
                door_dwells.append(trailer['door_dwell_hours'])

        avg_door_dwell = np.mean(door_dwells) if door_dwells else 0

        return {
            'avg_yard_dwell_hours': avg_dwell,
            'avg_moves_per_trailer': avg_moves,
            'avg_door_dwell_hours': avg_door_dwell,
            'total_trailers': len(self.trailers),
            'total_alerts': len(self.alerts),
            'target_yard_dwell_hours': 24,
            'target_door_dwell_hours': 2
        }
python
class YardManagementSystem:
    """
    Core yard management system functionality

    Track trailers, manage moves, monitor dwell time
    """

    def __init__(self):
        self.trailers = {}  # trailer_id -> trailer info
        self.yard_spots = {}  # spot_id -> trailer_id
        self.move_history = []
        self.alerts = []

    def check_in_trailer(self, trailer_id, carrier, seal_number,
                        trailer_type='dry_van', is_loaded=True):
        """
        Check in trailer at gate

        Creates trailer record in system
        """

        check_in_time = datetime.now()

        trailer_info = {
            'trailer_id': trailer_id,
            'carrier': carrier,
            'seal_number': seal_number,
            'trailer_type': trailer_type,
            'is_loaded': is_loaded,
            'status': 'in_yard',
            'check_in_time': check_in_time,
            'current_location': 'gate',
            'dock_door': None,
            'moves': 0
        }

        self.trailers[trailer_id] = trailer_info

        # Log move
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': check_in_time,
            'action': 'check_in',
            'location': 'gate'
        })

        return trailer_info

    def assign_yard_spot(self, trailer_id, spot_id):
        """
        Assign trailer to yard parking spot

        Parameters:
        - trailer_id: unique trailer identifier
        - spot_id: yard spot identifier
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        if spot_id in self.yard_spots and self.yard_spots[spot_id] is not None:
            return {'error': f'Spot {spot_id} already occupied'}

        # Update trailer location
        trailer = self.trailers[trailer_id]
        old_location = trailer['current_location']
        trailer['current_location'] = spot_id
        trailer['moves'] += 1

        # Update spot
        if old_location in self.yard_spots:
            self.yard_spots[old_location] = None  # Free old spot

        self.yard_spots[spot_id] = trailer_id

        # Log move
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'move_to_spot',
            'from': old_location,
            'to': spot_id
        })

        return {
            'trailer_id': trailer_id,
            'assigned_spot': spot_id,
            'moves': trailer['moves']
        }

    def spot_trailer_at_door(self, trailer_id, door_number):
        """
        Spot trailer at dock door for loading/unloading

        Parameters:
        - trailer_id: trailer to spot
        - door_number: dock door number
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        trailer = self.trailers[trailer_id]
        old_location = trailer['current_location']

        # Update trailer
        trailer['current_location'] = f'door_{door_number}'
        trailer['dock_door'] = door_number
        trailer['status'] = 'at_door'
        trailer['door_arrival_time'] = datetime.now()
        trailer['moves'] += 1

        # Free old spot if in yard
        if old_location in self.yard_spots:
            self.yard_spots[old_location] = None

        # Log move
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'spot_at_door',
            'door': door_number,
            'from': old_location
        })

        return {
            'trailer_id': trailer_id,
            'door': door_number,
            'spotted_time': trailer['door_arrival_time']
        }

    def complete_door_activity(self, trailer_id):
        """
        Complete loading/unloading at door

        Move trailer back to yard or check out
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        trailer = self.trailers[trailer_id]

        if trailer['status'] != 'at_door':
            return {'error': 'Trailer not at door'}

        # Calculate door dwell time
        door_dwell = (datetime.now() - trailer['door_arrival_time']).total_seconds() / 3600

        trailer['status'] = 'completed'
        trailer['door_departure_time'] = datetime.now()
        trailer['door_dwell_hours'] = door_dwell

        # Log
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'complete_door_activity',
            'door_dwell_hours': door_dwell
        })

        # Check for excessive door time (>2 hours)
        if door_dwell > 2:
            self.alerts.append({
                'alert_type': 'excessive_door_dwell',
                'trailer_id': trailer_id,
                'door_dwell_hours': door_dwell,
                'timestamp': datetime.now()
            })

        return {
            'trailer_id': trailer_id,
            'door_dwell_hours': door_dwell,
            'status': 'completed'
        }

    def check_out_trailer(self, trailer_id):
        """
        Check out trailer from facility

        Final step before trailer leaves
        """

        if trailer_id not in self.trailers:
            return {'error': f'Trailer {trailer_id} not found'}

        trailer = self.trailers[trailer_id]

        # Calculate total yard dwell
        total_dwell = (datetime.now() - trailer['check_in_time']).total_seconds() / 3600

        trailer['status'] = 'checked_out'
        trailer['check_out_time'] = datetime.now()
        trailer['total_yard_dwell_hours'] = total_dwell

        # Log
        self.move_history.append({
            'trailer_id': trailer_id,
            'timestamp': datetime.now(),
            'action': 'check_out',
            'total_dwell_hours': total_dwell
        })

        # Alert if excessive yard dwell (>24 hours)
        if total_dwell > 24:
            self.alerts.append({
                'alert_type': 'excessive_yard_dwell',
                'trailer_id': trailer_id,
                'total_dwell_hours': total_dwell,
                'timestamp': datetime.now()
            })

        return {
            'trailer_id': trailer_id,
            'total_yard_dwell_hours': total_dwell,
            'total_moves': trailer['moves']
        }

    def get_yard_status(self):
        """
        Get current yard status summary

        Returns counts by status
        """

        status_counts = {}
        for trailer in self.trailers.values():
            status = trailer['status']
            status_counts[status] = status_counts.get(status, 0) + 1

        total_trailers = len(self.trailers)
        occupied_spots = sum(1 for spot in self.yard_spots.values()
                           if spot is not None)

        return {
            'total_trailers_in_yard': total_trailers,
            'occupied_spots': occupied_spots,
            'by_status': status_counts,
            'active_alerts': len(self.alerts)
        }

    def find_trailer(self, trailer_id):
        """
        Locate trailer in yard

        Returns current location
        """

        if trailer_id not in self.trailers:
            return {'error': 'Trailer not found'}

        trailer = self.trailers[trailer_id]

        return {
            'trailer_id': trailer_id,
            'current_location': trailer['current_location'],
            'status': trailer['status'],
            'carrier': trailer['carrier'],
            'dwell_time_hours': (datetime.now() - trailer['check_in_time']).total_seconds() / 3600
        }

    def calculate_performance_metrics(self):
        """
        Calculate yard performance metrics

        Returns KPIs
        """

        if not self.trailers:
            return {'message': 'No data available'}

        # Average dwell time
        dwell_times = []
        for trailer in self.trailers.values():
            if 'total_yard_dwell_hours' in trailer:
                dwell_times.append(trailer['total_yard_dwell_hours'])

        avg_dwell = np.mean(dwell_times) if dwell_times else 0

        # Average moves per trailer
        moves = [t['moves'] for t in self.trailers.values()]
        avg_moves = np.mean(moves) if moves else 0

        # Door dwell times
        door_dwells = []
        for trailer in self.trailers.values():
            if 'door_dwell_hours' in trailer:
                door_dwells.append(trailer['door_dwell_hours'])

        avg_door_dwell = np.mean(door_dwells) if door_dwells else 0

        return {
            'avg_yard_dwell_hours': avg_dwell,
            'avg_moves_per_trailer': avg_moves,
            'avg_door_dwell_hours': avg_door_dwell,
            'total_trailers': len(self.trailers),
            'total_alerts': len(self.alerts),
            'target_yard_dwell_hours': 24,
            'target_door_dwell_hours': 2
        }

Example usage

Example usage

yms = YardManagementSystem()
yms = YardManagementSystem()

Check in trailer

Check in trailer

trailer = yms.check_in_trailer( trailer_id='TRL12345', carrier='ABC Trucking', seal_number='SEAL987', is_loaded=True ) print(f"Trailer {trailer['trailer_id']} checked in at {trailer['check_in_time']}")
trailer = yms.check_in_trailer( trailer_id='TRL12345', carrier='ABC Trucking', seal_number='SEAL987', is_loaded=True ) print(f"Trailer {trailer['trailer_id']} checked in at {trailer['check_in_time']}")

Assign to yard spot

Assign to yard spot

yms.assign_yard_spot('TRL12345', 'S045') print("Trailer assigned to spot S045")
yms.assign_yard_spot('TRL12345', 'S045') print("Trailer assigned to spot S045")

Spot at door

Spot at door

yms.spot_trailer_at_door('TRL12345', door_number=12) print("Trailer spotted at door 12")
yms.spot_trailer_at_door('TRL12345', door_number=12) print("Trailer spotted at door 12")

Get yard status

Get yard status

status = yms.get_yard_status() print(f"\nYard Status: {status['total_trailers_in_yard']} trailers in yard")

---
status = yms.get_yard_status() print(f"\nYard Status: {status['total_trailers_in_yard']} trailers in yard")

---

Yard Jockey Optimization

Yard Jockey优化

Jockey Dispatch & Task Management

Jockey调度与任务管理

python
class YardJockeyDispatcher:
    """
    Optimize yard jockey task assignment

    Minimize moves and maximize productivity
    """

    def __init__(self, num_jockeys, yard_layout):
        self.num_jockeys = num_jockeys
        self.yard_layout = yard_layout
        self.jockeys = {
            f'Jockey_{i+1}': {
                'current_location': 'office',
                'status': 'available',
                'tasks_completed': 0,
                'total_distance': 0
            }
            for i in range(num_jockeys)
        }
        self.task_queue = []

    def add_move_task(self, trailer_id, from_location, to_location, priority='normal'):
        """
        Add trailer move task to queue

        Parameters:
        - priority: 'urgent', 'normal', 'low'
        """

        task = {
            'task_id': f'TASK{len(self.task_queue)+1:04d}',
            'trailer_id': trailer_id,
            'from': from_location,
            'to': to_location,
            'priority': priority,
            'status': 'queued',
            'created_time': datetime.now()
        }

        self.task_queue.append(task)

        # Sort by priority
        priority_order = {'urgent': 0, 'normal': 1, 'low': 2}
        self.task_queue.sort(
            key=lambda x: priority_order.get(x['priority'], 1)
        )

        return task

    def assign_next_task(self):
        """
        Assign next task to available jockey

        Uses nearest jockey to minimize deadhead
        """

        # Find available jockey
        available_jockeys = [
            (jid, jinfo) for jid, jinfo in self.jockeys.items()
            if jinfo['status'] == 'available'
        ]

        if not available_jockeys or not self.task_queue:
            return None

        # Get next task
        task = self.task_queue[0]

        # Find nearest jockey
        nearest_jockey = None
        min_distance = float('inf')

        for jockey_id, jockey_info in available_jockeys:
            # Calculate distance from jockey to task start location
            distance = self._calculate_distance(
                jockey_info['current_location'],
                task['from']
            )

            if distance < min_distance:
                min_distance = distance
                nearest_jockey = jockey_id

        if nearest_jockey:
            # Assign task
            self.jockeys[nearest_jockey]['status'] = 'busy'
            self.jockeys[nearest_jockey]['current_task'] = task['task_id']

            task['status'] = 'in_progress'
            task['assigned_jockey'] = nearest_jockey
            task['start_time'] = datetime.now()

            self.task_queue.pop(0)

            return {
                'task_id': task['task_id'],
                'jockey': nearest_jockey,
                'trailer': task['trailer_id'],
                'move': f"{task['from']} -> {task['to']}"
            }

        return None

    def complete_task(self, task_id):
        """
        Mark task as completed

        Update jockey status and location
        """

        # Find task
        for task in self.task_queue:
            if task['task_id'] == task_id:
                task['status'] = 'completed'
                task['completion_time'] = datetime.now()

                # Update jockey
                jockey_id = task.get('assigned_jockey')
                if jockey_id:
                    self.jockeys[jockey_id]['status'] = 'available'
                    self.jockeys[jockey_id]['current_location'] = task['to']
                    self.jockeys[jockey_id]['tasks_completed'] += 1

                    # Calculate distance
                    distance = self._calculate_distance(task['from'], task['to'])
                    self.jockeys[jockey_id]['total_distance'] += distance

                return {
                    'task_id': task_id,
                    'jockey': jockey_id,
                    'status': 'completed'
                }

        return {'error': 'Task not found'}

    def _calculate_distance(self, location1, location2):
        """Calculate distance between two locations (simplified)"""

        # In practice, use actual yard coordinates
        # Simplified: random distance 50-500 feet
        return np.random.randint(50, 500)

    def get_jockey_productivity(self):
        """
        Calculate jockey productivity metrics

        Returns moves per hour, utilization
        """

        productivity = []

        for jockey_id, jockey_info in self.jockeys.items():
            productivity.append({
                'jockey_id': jockey_id,
                'tasks_completed': jockey_info['tasks_completed'],
                'total_distance': jockey_info['total_distance'],
                'current_status': jockey_info['status']
            })

        return pd.DataFrame(productivity)

    def optimize_task_sequence(self, tasks):
        """
        Optimize sequence of tasks to minimize total distance

        Uses greedy nearest-neighbor approach
        """

        if not tasks:
            return []

        optimized_sequence = []
        remaining_tasks = tasks.copy()
        current_location = 'office'

        while remaining_tasks:
            # Find nearest task
            nearest_task = None
            min_distance = float('inf')

            for task in remaining_tasks:
                distance = self._calculate_distance(
                    current_location,
                    task['from']
                )

                if distance < min_distance:
                    min_distance = distance
                    nearest_task = task

            if nearest_task:
                optimized_sequence.append(nearest_task)
                remaining_tasks.remove(nearest_task)
                current_location = nearest_task['to']

        return optimized_sequence

python
class YardJockeyDispatcher:
    """
    Optimize yard jockey task assignment

    Minimize moves and maximize productivity
    """

    def __init__(self, num_jockeys, yard_layout):
        self.num_jockeys = num_jockeys
        self.yard_layout = yard_layout
        self.jockeys = {
            f'Jockey_{i+1}': {
                'current_location': 'office',
                'status': 'available',
                'tasks_completed': 0,
                'total_distance': 0
            }
            for i in range(num_jockeys)
        }
        self.task_queue = []

    def add_move_task(self, trailer_id, from_location, to_location, priority='normal'):
        """
        Add trailer move task to queue

        Parameters:
        - priority: 'urgent', 'normal', 'low'
        """

        task = {
            'task_id': f'TASK{len(self.task_queue)+1:04d}',
            'trailer_id': trailer_id,
            'from': from_location,
            'to': to_location,
            'priority': priority,
            'status': 'queued',
            'created_time': datetime.now()
        }

        self.task_queue.append(task)

        # Sort by priority
        priority_order = {'urgent': 0, 'normal': 1, 'low': 2}
        self.task_queue.sort(
            key=lambda x: priority_order.get(x['priority'], 1)
        )

        return task

    def assign_next_task(self):
        """
        Assign next task to available jockey

        Uses nearest jockey to minimize deadhead
        """

        # Find available jockey
        available_jockeys = [
            (jid, jinfo) for jid, jinfo in self.jockeys.items()
            if jinfo['status'] == 'available'
        ]

        if not available_jockeys or not self.task_queue:
            return None

        # Get next task
        task = self.task_queue[0]

        # Find nearest jockey
        nearest_jockey = None
        min_distance = float('inf')

        for jockey_id, jockey_info in available_jockeys:
            # Calculate distance from jockey to task start location
            distance = self._calculate_distance(
                jockey_info['current_location'],
                task['from']
            )

            if distance < min_distance:
                min_distance = distance
                nearest_jockey = jockey_id

        if nearest_jockey:
            # Assign task
            self.jockeys[nearest_jockey]['status'] = 'busy'
            self.jockeys[nearest_jockey]['current_task'] = task['task_id']

            task['status'] = 'in_progress'
            task['assigned_jockey'] = nearest_jockey
            task['start_time'] = datetime.now()

            self.task_queue.pop(0)

            return {
                'task_id': task['task_id'],
                'jockey': nearest_jockey,
                'trailer': task['trailer_id'],
                'move': f"{task['from']} -> {task['to']}"
            }

        return None

    def complete_task(self, task_id):
        """
        Mark task as completed

        Update jockey status and location
        """

        # Find task
        for task in self.task_queue:
            if task['task_id'] == task_id:
                task['status'] = 'completed'
                task['completion_time'] = datetime.now()

                # Update jockey
                jockey_id = task.get('assigned_jockey')
                if jockey_id:
                    self.jockeys[jockey_id]['status'] = 'available'
                    self.jockeys[jockey_id]['current_location'] = task['to']
                    self.jockeys[jockey_id]['tasks_completed'] += 1

                    # Calculate distance
                    distance = self._calculate_distance(task['from'], task['to'])
                    self.jockeys[jockey_id]['total_distance'] += distance

                return {
                    'task_id': task_id,
                    'jockey': jockey_id,
                    'status': 'completed'
                }

        return {'error': 'Task not found'}

    def _calculate_distance(self, location1, location2):
        """Calculate distance between two locations (simplified)"""

        # In practice, use actual yard coordinates
        # Simplified: random distance 50-500 feet
        return np.random.randint(50, 500)

    def get_jockey_productivity(self):
        """
        Calculate jockey productivity metrics

        Returns moves per hour, utilization
        """

        productivity = []

        for jockey_id, jockey_info in self.jockeys.items():
            productivity.append({
                'jockey_id': jockey_id,
                'tasks_completed': jockey_info['tasks_completed'],
                'total_distance': jockey_info['total_distance'],
                'current_status': jockey_info['status']
            })

        return pd.DataFrame(productivity)

    def optimize_task_sequence(self, tasks):
        """
        Optimize sequence of tasks to minimize total distance

        Uses greedy nearest-neighbor approach
        """

        if not tasks:
            return []

        optimized_sequence = []
        remaining_tasks = tasks.copy()
        current_location = 'office'

        while remaining_tasks:
            # Find nearest task
            nearest_task = None
            min_distance = float('inf')

            for task in remaining_tasks:
                distance = self._calculate_distance(
                    current_location,
                    task['from']
                )

                if distance < min_distance:
                    min_distance = distance
                    nearest_task = task

            if nearest_task:
                optimized_sequence.append(nearest_task)
                remaining_tasks.remove(nearest_task)
                current_location = nearest_task['to']

        return optimized_sequence

Common Challenges & Solutions

常见挑战与解决方案

Challenge: Trailer Visibility

挑战:拖车可见性不足

Problem:
  • Can't find trailers in yard
  • Drivers search for 15-30 minutes
  • Wasted time and frustration
Solutions:
  • Implement YMS with GPS/RFID tracking
  • Zone-based yard layout with clear signage
  • Mobile app for drivers (trailer locator)
  • Digital yard map with real-time updates
  • Dedicated staging zones by status
  • Color-coded yard spots
  • Regular yard audits to verify locations
问题:
  • 无法在堆场中找到拖车
  • 司机需花费15-30分钟寻找
  • 时间浪费与人员不满
解决方案:
  • 部署带有GPS/RFID跟踪功能的YMS
  • 采用分区堆场布局并设置清晰标识
  • 为司机提供拖车定位移动应用
  • 实时更新的数字化堆场地图
  • 按状态划分专用 staging zones
  • 泊位颜色编码
  • 定期堆场审计以验证拖车位置

Challenge: High Detention Costs

挑战:高额滞留费用

Problem:
  • Paying detention fees ($50-100/hour)
  • Trailers sitting at doors too long
  • Slow loading/unloading
Solutions:
  • Set hard time limits for door dwell (<2 hours)
  • Monitor and alert on approaching detention
  • Pre-stage loads (ready before truck arrives)
  • Live loading/unloading where possible
  • Negotiate detention grace periods
  • Optimize dock scheduling (avoid overbooking)
  • Cross-training to flex labor to doors
  • Automated alerts at 75% of free time
问题:
  • 支付滞留费(每小时50-100美元)
  • 拖车在码头门停留时间过长
  • 装卸速度缓慢
解决方案:
  • 设置码头门停留硬限制(<2小时)
  • 监控并在接近滞留时限时发出警报
  • 预装载货物(卡车到达前准备就绪)
  • 尽可能采用实时装卸
  • 协商滞留宽限期
  • 优化码头调度(避免过度预订)
  • 交叉培训员工以灵活支援码头作业
  • 在免费时间达到75%时自动发出警报

Challenge: Yard Congestion

挑战:堆场拥堵

Problem:
  • Too many trailers, not enough space
  • Difficulty maneuvering jockeys
  • Blocked access to trailers
Solutions:
  • Implement drop trailer program (pre-loaded outbound)
  • Dedicated empty trailer pool off-site
  • Just-in-time arrival scheduling
  • Turn away non-appointment arrivals
  • Expand yard capacity or use overflow lot
  • Improve trailer turn time (reduce dwell)
  • Better appointment scheduling (smooth arrivals)
问题:
  • 拖车过多,空间不足
  • 堆场调度员难以操作
  • 拖车通道被阻塞
解决方案:
  • 实施drop trailer program(预装载 outbound拖车)
  • 在场外设置专用空拖车池
  • 准时到达调度
  • 拒绝无预约到达的车辆
  • 扩大堆场容量或使用溢出场地
  • 缩短拖车周转时间(减少停留)
  • 优化预约调度(平滑到达高峰)

Challenge: Long Wait Times at Gate

挑战:闸口等待时间过长

Problem:
  • Trucks waiting 30-60 minutes at gate
  • Manual check-in process slow
  • Paperwork errors and delays
Solutions:
  • Implement online pre-check-in portal
  • Use kiosks for self-check-in
  • Dedicated lanes for pre-registered drivers
  • Automate BOL scanning and validation
  • Pre-approve appointments (pre-verify credentials)
  • Add gate capacity (more lanes)
  • Mobile check-in before arrival
问题:
  • 卡车在闸口等待30-60分钟
  • 人工登记流程缓慢
  • 文件错误与延误
解决方案:
  • 实施在线预登记门户
  • 使用自助登记 kiosks
  • 为预注册司机设置专用通道
  • 自动化BOL扫描与验证
  • 预先批准预约(提前验证资质)
  • 增加闸口容量(更多通道)
  • 到达前移动登记

Challenge: Inefficient Jockey Utilization

挑战:Yard Jockey利用率低下

Problem:
  • Jockeys idle or making unnecessary moves
  • Long deadhead distances
  • Poor task prioritization
Solutions:
  • Implement jockey dispatch system
  • Zone-based jockey assignments
  • Real-time task queue with priorities
  • Optimize task sequencing (minimize distance)
  • Right-size jockey staffing
  • Cross-train warehouse staff as backup
  • Performance metrics and incentives
问题:
  • Yard Jockey闲置或进行不必要的调度
  • 空驶距离过长
  • 任务优先级设置不合理
解决方案:
  • 实施Jockey调度系统
  • 分区分配Jockey任务
  • 带优先级的实时任务队列
  • 优化任务顺序(最小化距离)
  • 合理配置Jockey人员数量
  • 交叉培训仓库员工作为后备
  • 绩效指标与激励机制

Challenge: Lack of Appointment Compliance

挑战:预约合规性差

Problem:
  • Carriers show up without appointments
  • Early or late arrivals disrupt schedule
  • Overbooking of doors
Solutions:
  • Require appointments (enforce policy)
  • Charge premium for non-appointment arrivals
  • Communicate appointment importance
  • Partner with carriers on compliance
  • Send appointment reminders (day before, morning of)
  • Track and report carrier compliance
  • Refuse service to repeat offenders

问题:
  • 承运人无预约到场
  • 早到或迟到打乱调度计划
  • 码头门过度预订
解决方案:
  • 强制要求预约(执行政策)
  • 对无预约到达收取额外费用
  • 沟通预约的重要性
  • 与承运人合作提升合规性
  • 发送预约提醒(前一天、当天早上)
  • 跟踪并报告承运人合规情况
  • 拒绝屡犯者服务

Yard Management Technology

堆场管理技术

Yard Management System (YMS) Selection

堆场管理系统(YMS)选型

Enterprise YMS Platforms:
  • C3 Solutions: Industry leader
  • Zebra (formerly Yard Management Solutions): RFID-based
  • Manhattan Associates YMS: WMS-integrated
  • Oracle Yard Management: Cloud-based
  • Blue Yonder YMS: AI-powered
  • 4Sight Yard Management: Mid-market
Key YMS Features:
  • Real-time trailer tracking (GPS, RFID, manual)
  • Gate check-in/check-out automation
  • Dock appointment scheduling
  • Jockey task management and dispatch
  • Dwell time monitoring and alerts
  • Reporting and analytics
  • Integration with WMS and TMS
企业级YMS平台:
  • C3 Solutions:行业领导者
  • Zebra (formerly Yard Management Solutions):基于RFID的系统
  • Manhattan Associates YMS:与WMS集成
  • Oracle Yard Management:云平台
  • Blue Yonder YMS:AI驱动
  • 4Sight Yard Management:面向中端市场
YMS核心功能:
  • 实时拖车跟踪(GPS、RFID、手动)
  • 闸口登记/注销自动化
  • 码头预约调度
  • Jockey任务管理与调度
  • 停留时间监控与警报
  • 报告与分析
  • 与WMS和TMS集成

Tracking Technologies

跟踪技术

RFID Tags:
  • Passive tags on trailers
  • Readers at gates and key points
  • Automatic location updates
  • Cost: $5-10 per tag, $1K-5K per reader
GPS Tracking:
  • Active GPS devices on trailers
  • Real-time location accuracy
  • Higher cost, requires power
  • Cost: $50-150 per device + monthly fees
Geofencing:
  • Virtual boundaries in yard
  • Trigger alerts when crossed
  • Works with GPS or RFID
Barcode/QR Scanning:
  • Low-tech, manual scanning
  • Mobile app for jockeys
  • Lower accuracy, requires compliance

RFID标签:
  • 拖车搭载被动标签
  • 闸口与关键位置部署阅读器
  • 自动更新位置
  • 成本:每个标签5-10美元,每个阅读器1000-5000美元
GPS跟踪:
  • 拖车搭载主动GPS设备
  • 实时位置精准
  • 成本较高,需供电
  • 成本:每个设备50-150美元 + 月服务费
地理围栏(Geofencing):
  • 堆场虚拟边界
  • 越界时触发警报
  • 可与GPS或RFID配合使用
条码/QR码扫描:
  • 低技术成本,手动扫描
  • 为Jockey提供移动应用
  • 准确性较低,需合规操作

Output Format

输出格式

Yard Management Analysis Report

堆场管理分析报告

Executive Summary:
  • Average yard dwell time: 18.5 hours (target: <12 hours)
  • Detention costs: $18,500/month (target: <$10,000)
  • Door utilization: 62% (target: 75%)
  • Yard capacity utilization: 85% (near capacity)
  • Recommendation: Implement YMS, improve dock scheduling
Current State Metrics:
MetricCurrentTargetStatus
Avg yard dwell time18.5 hrs<12 hrs⚠️ 54% over
Avg door dwell time2.8 hrs<2 hrs⚠️ 40% over
Detention costs/month$18.5K<$10K⚠️ 85% over
Gate wait time22 min<10 min⚠️ 120% over
Door utilization62%75%⚠️ Below target
Yard occupancy85%80%⚠️ Near capacity
Detention Cost Analysis:
CarrierMonthly ChargesIncidentsAvg DurationRoot Cause
Carrier A$6,200423.2 hrsSlow unloading
Carrier B$4,800352.9 hrsDock congestion
Carrier C$3,500282.6 hrsMissing appointments
Others$4,000322.5 hrsVarious
Yard Dwell Time by Status:
Trailer StatusCountAvg DwellMax Dwell% Over 24 hrs
Inbound staged4512.5 hrs38 hrs15%
At door (loading)182.8 hrs4.5 hrs0%
Outbound ready3228.0 hrs72 hrs45% ⚠️
Empty/Drop2536.0 hrs120 hrs60% ⚠️
Root Cause: Outbound Delays
  • Waiting for consolidation (3+ days)
  • No carrier pickup scheduled
  • Recommendation: Daily pickup schedule or use 3PL
Door Utilization by Day/Time:
Time SlotMonTueWedThuFriAvg
6-9 AM85%82%88%90%85%86%
9-12 PM75%70% 72%78%75%74%
12-3 PM55%52%58%60%55%56% ⚠️
3-6 PM48%45%50%52%48%49% ⚠️
Recommendation: Evening shift to utilize afternoons
Improvement Initiatives:
  1. Implement YMS - Impact: -30% dwell time, -40% detention
    • Real-time trailer tracking
    • Automated door scheduling
    • Jockey dispatch optimization
    • Investment: $180K, ROI: 14 months
  2. Optimize Dock Scheduling - Impact: +13% door utilization
    • Implement appointment system
    • Enforce appointment compliance
    • Balance arrivals throughout day
    • Investment: $25K (software)
  3. Reduce Outbound Dwell - Impact: -50% yard congestion
    • Daily carrier pickup schedule
    • Pre-loaded outbound staging
    • Drop trailer program
    • Savings: $120K annually
  4. Expand Gate Capacity - Impact: -60% wait time
    • Add second gate lane
    • Self-service kiosk check-in
    • Pre-registration portal
    • Investment: $75K
Expected Results (12 months):
MetricCurrentTargetImprovement
Avg yard dwell18.5 hrs12 hrs-35%
Detention costs$18.5K/mo$9K/mo-51%
Door utilization62%75%+13 pts
Gate wait time22 min8 min-64%
Yard occupancy85%70%-15 pts

执行摘要:
  • 平均堆场停留时间:18.5小时(目标:<12小时)
  • 滞留成本:每月18,500美元(目标:<10,000美元)
  • 码头门利用率:62%(目标:75%)
  • 堆场容量利用率:85%(接近饱和)
  • 建议:部署YMS,优化码头调度
当前状态指标:
指标当前值目标值状态
平均堆场停留时间18.5小时<12小时⚠️ 超出54%
平均码头门停留时间2.8小时<2小时⚠️ 超出40%
月度滞留成本18,500美元<10,000美元⚠️ 超出85%
闸口等待时间22分钟<10分钟⚠️ 超出120%
码头门利用率62%75%⚠️ 低于目标
堆场占用率85%80%⚠️ 接近饱和
滞留成本分析:
承运人月度费用事件数平均时长根本原因
Carrier A6,200美元423.2小时卸货缓慢
Carrier B4,800美元352.9小时码头拥堵
Carrier C3,500美元282.6小时未预约
其他4,000美元322.5小时多种原因
按状态划分的堆场停留时间:
拖车状态数量平均停留时间最长停留时间停留超24小时占比
入港待处理4512.5小时38小时15%
码头装卸中182.8小时4.5小时0%
出港就绪3228.0小时72小时45% ⚠️
空车/落放2536.0小时120小时60% ⚠️
根本原因:出港延误
  • 等待合并(3天以上)
  • 未安排承运人提货
  • 建议:每日提货计划或使用第三方物流(3PL)
按日期/时段划分的码头门利用率:
时段周一周二周三周四周五平均值
6-9点85%82%88%90%85%86%
9-12点75%70%72%78%75%74%
12-15点55%52%58%60%55%56% ⚠️
15-18点48%45%50%52%48%49% ⚠️
建议:增设晚班以利用下午时段
改进举措:
  1. 部署YMS - 影响:停留时间减少30%,滞留成本降低40%
    • 实时拖车跟踪
    • 自动化码头调度
    • Jockey调度优化
    • 投资:180,000美元,投资回报周期:14个月
  2. 优化码头调度 - 影响:码头门利用率提升13%
    • 实施预约系统
    • 强制预约合规
    • 平衡全天到达量
    • 投资:25,000美元(软件)
  3. 减少出港停留时间 - 影响:堆场拥堵减少50%
    • 每日承运人提货计划
    • 预装载出港 staging
    • drop trailer program
    • 年节省:120,000美元
  4. 扩大闸口容量 - 影响:等待时间减少60%
    • 增设第二条闸口通道
    • 自助登记 kiosk
    • 预注册门户
    • 投资:75,000美元
预期结果(12个月后):
指标当前值目标值改进幅度
平均堆场停留时间18.5小时12小时-35%
滞留成本18,500美元/月9,000美元/月-51%
码头门利用率62%75%+13个百分点
闸口等待时间22分钟8分钟-64%
堆场占用率85%70%-15个百分点

Questions to Ask

需询问的问题

If you need more context:
  1. How many dock doors and yard spots?
  2. What's your daily trailer volume (in/out)?
  3. Do you have a YMS or tracking system?
  4. What's your average yard dwell time?
  5. Are you paying detention costs? How much?
  6. Any appointment scheduling system?
  7. How many yard jockeys/tractors?
  8. Main pain points? (visibility, congestion, detention, wait times)

如需更多背景信息,请询问:
  1. 码头门和堆场泊位数量是多少?
  2. 每日拖车进出量是多少?
  3. 是否已部署YMS或跟踪系统?
  4. 平均堆场停留时间是多少?
  5. 是否支付滞留费用?金额多少?
  6. 是否有预约调度系统?
  7. Yard Jockey/牵引车数量是多少?
  8. 主要痛点是什么?(可见性、拥堵、滞留、等待时间)

Related Skills

相关技能

  • dock-door-assignment: Optimize dock door scheduling and assignment
  • cross-docking: Cross-dock operations and flow-through
  • warehouse-design: Facility layout and design
  • route-optimization: Outbound routing and delivery
  • freight-optimization: Carrier management and transportation
  • supply-chain-automation: Automation and technology selection
  • process-optimization: Operational process improvement
  • maintenance-planning: Equipment and yard tractor maintenance
  • dock-door-assignment:优化码头门调度与分配
  • cross-docking:交叉码头作业与流转
  • warehouse-design:设施布局与设计
  • route-optimization:出港路线与配送优化
  • freight-optimization:承运人管理与运输优化
  • supply-chain-automation:自动化与技术选型
  • process-optimization:运营流程改进
  • maintenance-planning:设备与堆场牵引车维护