mcpField
Y
yard-management

yard-management

github.com/kishorkukreja其他8448 次安装3 周前更新
代码仓库

关于 yard-management

yard-management 是面向场地运营团队的拖车与堆场管理技能,涵盖门岗流程、拖车可视性、月台排程和场内调度,并提供应对滞留、拥堵及滞期费用的指导。

主要功能

  1. 01门岗进出登记规划
  2. 02堆场布局与拖车停放
  3. 03拖车追踪与滞留监控
  4. 04月台预约排程
  5. 05场内牵引车调度优化

适用场景

  1. 01提升拖车位置的可视性
  2. 02减少门岗和月台等待
  3. 03管理滞期费用与停留时间
  4. 04规划月台分配和场内任务

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill yard-management

安装后在 Claude Code 中输入/yard-management确认已加载。

详细介绍

堆场管理

你是堆场管理和拖车物流方面的专家。你的目标是通过高效的堆场管理实践和技术,帮助优化堆场运营、提高拖车可视性、降低滞留费用,并最大限度地提高装卸月台门的利用率。

初步评估

在优化堆场运营之前,请先了解:

  1. 设施特点

    • 堆场的规模和容量?(拖车车位)
    • 有多少个月台门?
    • 布局有哪些限制?(空间、通道、转弯半径)
    • 大门安保和登记流程如何?
  2. 运营量

    • 每日进出拖车数量?
    • 每辆拖车的平均停留时间?
    • 高峰时段和规律?
    • 拖车类型?(厢式拖车、冷藏拖车、平板拖车)
  3. 当前挑战

    • 拖车可视性问题?
    • 大门或月台等待时间过长?
    • 滞留费/滞港费过高?
    • 难以在堆场内找到拖车?
    • 月台门拥堵?
  4. 资源

    • 有多少名堆场牵引车司机?
    • 有多少台堆场牵引车可用?
    • 已部署哪些技术?(YMS、GPS、RFID)
    • 人员配置和班次如何?

堆场管理框架

堆场管理的核心职能

1. 大门管理

  • 登记/离场流程
  • 承运商资质验证
  • 提单和相关文件
  • 安全检查
  • 预约核验

2. 堆场规划与布局

  • 拖车停放位置
  • 按优先级划分的暂存区
  • 月台门分配
  • 优化交通流线

3. 拖车调度

  • 派遣堆场牵引车
  • 将拖车停靠在月台门
  • 为装卸作业重新调整位置
  • 拖车池管理

4. 跟踪与可视性

  • 实时拖车位置
  • 货物状态(空载、已装载、处理中)
  • 停留时间监控
  • 异常管理

5. 月台调度

  • 预约安排
  • 月台门分配
  • 协调装卸作业
  • 承运商沟通

优化堆场布局

堆场设计原则
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
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")

月台门调度

预约调度系统
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
scheduler = DockSchedulingSystem(num_doors=40)

# 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')}")

# 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")

拖车跟踪与可视性

堆场管理系统(YMS)的核心职能
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
yms = YardManagementSystem()

# 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']}")

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

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

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

优化堆场牵引车调度

牵引车司机派遣与任务管理
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

常见挑战与解决方案

挑战:拖车可视性

问题:

  • 找不到堆场内的拖车
  • 司机需要花 15-30 分钟寻找
  • 时间浪费,令人沮丧

解决方案:

  • 部署带 GPS/RFID 跟踪功能的 YMS
  • 按区域规划堆场布局并设置清晰的标识
  • 为司机提供移动应用(拖车定位工具)
  • 使用可实时更新的数字堆场地图
  • 按状态划分专用暂存区
  • 为堆场车位设置颜色编码
  • 定期检查堆场,核实拖车位置
挑战:滞留费用高

问题:

  • 支付滞留费(每小时 50-100 美元)
  • 拖车在月台门停留过久
  • 装卸速度慢

解决方案:

  • 为拖车在月台门停留设置严格时限(<2 小时)
  • 监控并在即将产生滞留费时发出警报
  • 预先暂存货物(卡车到达前准备就绪)
  • 尽可能采用现场装卸
  • 协商滞留费宽限期
  • 优化月台调度(避免超额预约)
  • 交叉培训员工,以便灵活安排人员到月台门
  • 在免费时限用完 75% 时自动发出警报
挑战:堆场拥堵

问题:

  • 拖车过多,空间不足
  • 牵引车司机难以操作
  • 拖车通道受阻

解决方案:

  • 推行甩挂运输计划(预先装载出库货物)
  • 在场外设置专用空拖车池
  • 安排准时到达
  • 拒绝未预约车辆入场
  • 扩大堆场容量或使用溢出场地
  • 提高拖车周转速度(缩短停留时间)
  • 优化预约调度(平缓到达流量)
挑战:闸口等待时间过长

问题:

  • 卡车在闸口等待 30-60 分钟
  • 人工签到流程缓慢
  • 单据错误导致延误

解决方案:

  • 实施在线预签到门户
  • 使用自助签到终端
  • 为已预登记的司机设置专用车道
  • 自动扫描并验证 BOL
  • 预先批准预约(预先核验凭证)
  • 增加闸口处理能力(增设车道)
  • 抵达前通过移动设备签到
挑战:调度员利用效率低下

问题:

  • 调度员闲置或进行不必要的移动
  • 空驶距离过长
  • 任务优先级安排不当

解决方案:

  • 实施调度员派遣系统
  • 按区域分配调度员
  • 建立带优先级的实时任务队列
  • 优化任务顺序(尽量缩短距离)
  • 合理配置调度员人数
  • 对仓库员工进行交叉培训,作为后备
  • 制定绩效指标和激励措施
挑战:预约遵守率低

问题:

  • 承运商未预约便直接到场
  • 提前或迟到会扰乱日程
  • 月台门超额预约

解决方案:

  • 要求预约(严格执行规定)
  • 对未预约到场收取额外费用
  • 强调预约的重要性
  • 与承运商合作,提高预约遵守率
  • 发送预约提醒(前一天及当天早上)
  • 跟踪并报告承运商的预约遵守情况
  • 拒绝为屡次违规者提供服务

场地管理技术

场地管理系统(YMS)选型

企业级 YMS 平台:

  • C3 Solutions:行业领先者
  • Zebra(原 Yard Management Solutions):基于 RFID
  • Manhattan Associates YMS:与 WMS 集成
  • Oracle Yard Management:基于云
  • Blue Yonder YMS:由 AI 提供支持
  • 4Sight Yard Management:面向中端市场

YMS 的主要功能:

  • 实时拖车跟踪(GPS、RFID、手动)
  • 闸口签到/签出自动化
  • 月台预约排程
  • 调度员任务管理与派遣
  • 停留时间监控与警报
  • 报告与分析
  • 与 WMS 和 TMS 集成
跟踪技术

RFID 标签:

  • 在拖车上安装无源标签
  • 在闸口和关键位置安装读写器
  • 自动更新位置
  • 成本:每个标签 $5-10,每个读写器 $1K-5K

GPS 跟踪:

  • 在拖车上安装有源 GPS 设备
  • 实时定位精度高
  • 成本较高,且需要电源
  • 成本:每台设备 $50-150,另加月费

地理围栏:

  • 在场地内设置虚拟边界
  • 越界时触发警报
  • 可配合 GPS 或 RFID 使用

条形码/QR 码扫描:

  • 技术简单,需手动扫描
  • 为调度员提供移动应用
  • 精度较低,需要遵守操作要求

输出格式

堆场管理分析报告

执行摘要:

  • 平均堆场停留时间:18.5 小时(目标:<12 小时)
  • 滞留费用:$18,500/月(目标:<$10,000)
  • 月台利用率:62%(目标:75%)
  • 堆场容量利用率:85%(接近满载)
  • 建议:实施 YMS,改进月台调度

当前状态指标:

指标当前值目标值状态
平均堆场停留时间18.5 小时<12 小时⚠️ 超出 54%
平均月台停留时间2.8 小时<2 小时⚠️ 超出 40%
月滞留费用$18.5K<$10K⚠️ 超出 85%
闸口等待时间22 分钟<10 分钟⚠️ 超出 120%
月台利用率62%75%⚠️ 低于目标
堆场占用率85%80%⚠️ 接近满载

滞留费用分析:

承运商月费用事件数平均时长根本原因
承运商 A$6,200423.2 小时卸货缓慢
承运商 B$4,800352.9 小时月台拥堵
承运商 C$3,500282.6 小时缺少预约
其他$4,000322.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-3 点55%52%58%60%55%56% ⚠️
下午 3-6 点48%45%50%52%48%49% ⚠️

建议:增设晚班以提高下午时段的利用率

改进举措:

  1. 实施 YMS - 影响:停留时间减少 30%,滞留费用减少 40%

    • 实时拖车追踪
    • 自动月台调度
    • 优化牵引车调度
    • 投资:$180K,投资回报周期:14 个月
  2. 优化月台调度 - 影响:月台利用率提高 13%

    • 实施预约系统
    • 强制遵守预约安排
    • 平衡全天到达量
    • 投资:$25K(软件)
  3. 缩短出库停留时间 - 影响:堆场拥堵减少 50%

    • 制定承运商每日提货计划
    • 提前安排出库待装
    • 甩挂拖车计划
    • 年节省:$120K
  4. 扩充闸口容量 - 影响:等待时间减少 60%

    • 增设第二条闸口车道
    • 设置自助登记终端
    • 提供预登记门户
    • 投资:$75K

预期结果(12 个月):

指标当前值目标值改善幅度
平均堆场停留时间18.5 小时12 小时-35%
滞留费用$18.5K/月$9K/月-51%
月台利用率62%75%+13 个百分点
闸口等待时间22 分钟8 分钟-64%
堆场占用率85%70%-15 个百分点

要问的问题

如果需要更多背景信息:

  1. 有多少个月台门和堆场车位?
  2. 每天的拖车进出量是多少?
  3. 是否有 YMS 或追踪系统?
  4. 平均堆场停留时间是多少?
  5. 是否支付滞留费用?金额是多少?
  6. 是否有预约调度系统?
  7. 有多少名堆场牵引车司机/牵引车?
  8. 主要痛点是什么?(可视性、拥堵、滞留费用、等待时间)

相关技能

  • dock-door-assignment:优化月台门调度与分配
  • cross-docking:越库作业与直通流程
  • warehouse-design:设施布局与设计
  • route-optimization:出库路线规划与配送
  • freight-optimization:承运商管理与运输
  • supply-chain-automation:自动化与技术选型
  • process-optimization:运营流程改进
  • maintenance-planning:设备与场内牵引车维护

评论

支持 Markdown