flower_mr 1 месяц назад
Родитель
Сommit
122200a14e

BIN
bin/__pycache__/models.cpython-38.pyc


BIN
bin/__pycache__/views.cpython-38.pyc


+ 55 - 0
bin/migrations/0011_base_location_remove_alloction_pre_layer1_pressure_and_more.py

@@ -0,0 +1,55 @@
+# Generated by Django 4.1.2 on 2025-04-20 14:13
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('bin', '0010_remove_alloction_pre_layer1_pre_and_more'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='base_location',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('layer1_pressure', models.IntegerField(default=0, verbose_name='第一层工作压力')),
+                ('layer2_pressure', models.IntegerField(default=0, verbose_name='第二层工作压力')),
+                ('layer3_pressure', models.IntegerField(default=0, verbose_name='第三层工作压力')),
+            ],
+            options={
+                'verbose_name': 'Base_location',
+                'verbose_name_plural': 'Base_location',
+                'db_table': 'base_location',
+                'ordering': ['-id'],
+            },
+        ),
+        migrations.RemoveField(
+            model_name='alloction_pre',
+            name='layer1_pressure',
+        ),
+        migrations.RemoveField(
+            model_name='alloction_pre',
+            name='layer2_pressure',
+        ),
+        migrations.RemoveField(
+            model_name='alloction_pre',
+            name='layer3_pressure',
+        ),
+        migrations.AddField(
+            model_name='alloction_pre',
+            name='layer1_task_finish_number',
+            field=models.IntegerField(default=0, verbose_name='第一层任务完成数'),
+        ),
+        migrations.AddField(
+            model_name='alloction_pre',
+            name='layer2_task_finish_number',
+            field=models.IntegerField(default=0, verbose_name='第二层任务完成数'),
+        ),
+        migrations.AddField(
+            model_name='alloction_pre',
+            name='layer3_task_finish_number',
+            field=models.IntegerField(default=0, verbose_name='第三层任务完成数'),
+        ),
+    ]

+ 18 - 0
bin/migrations/0012_alloction_pre_layer_solution_type.py

@@ -0,0 +1,18 @@
+# Generated by Django 4.1.2 on 2025-04-20 16:03
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('bin', '0011_base_location_remove_alloction_pre_layer1_pressure_and_more'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='alloction_pre',
+            name='layer_solution_type',
+            field=models.JSONField(default=list, verbose_name='规划方案'),
+        ),
+    ]

BIN
bin/migrations/__pycache__/0011_base_location_remove_alloction_pre_layer1_pressure_and_more.cpython-38.pyc


BIN
bin/migrations/__pycache__/0012_alloction_pre_layer_solution_type.cpython-38.pyc


+ 17 - 3
bin/models.py

@@ -921,15 +921,29 @@ class LocationChangeLog(models.Model):
         verbose_name_plural = "Location Change Log"
         ordering = ['-id']
 
+class base_location(models.Model):
+
+    layer1_pressure = models.IntegerField(default=0, verbose_name='第一层工作压力')
+    layer2_pressure = models.IntegerField(default=0, verbose_name='第二层工作压力')
+    layer3_pressure = models.IntegerField(default=0, verbose_name='第三层工作压力')
+    class Meta:
+        db_table = 'base_location'
+        verbose_name = 'Base_location'
+        verbose_name_plural = "Base_location"
+        ordering = ['-id']
+
+
 class alloction_pre(models.Model):
 
     batch_number = models.CharField(max_length=255, verbose_name='批次号')
 
     layer_pre_type = models.JSONField(default=list, verbose_name='预留方案')
+    layer_solution_type = models.JSONField(default=list, verbose_name='规划方案')
 
-    layer1_pressure = models.IntegerField(default=0, verbose_name='第一层工作压力')
-    layer2_pressure = models.IntegerField(default=0, verbose_name='第二层工作压力')
-    layer3_pressure = models.IntegerField(default=0, verbose_name='第三层工作压力')
+
+    layer1_task_finish_number = models.IntegerField(default=0, verbose_name='第一层任务完成数')
+    layer2_task_finish_number = models.IntegerField(default=0, verbose_name='第二层任务完成数')
+    layer3_task_finish_number = models.IntegerField(default=0, verbose_name='第三层任务完成数')
 
     create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
     class Meta:

+ 145 - 101
bin/views.py

@@ -11,7 +11,7 @@ from django.utils import timezone
 from django.db import transaction
 import logging
 from rest_framework import status
-from .models import DeviceModel,LocationModel,LocationGroupModel,LocationContainerLink,LocationChangeLog,alloction_pre
+from .models import DeviceModel,LocationModel,LocationGroupModel,LocationContainerLink,LocationChangeLog,alloction_pre,base_location
 from bound.models import BoundBatchModel,BoundDetailModel,BoundListModel
 
 
@@ -524,76 +524,53 @@ class LocationAllocation:
         batch = container_detail.batch.bound_number
         return batch
     @transaction.atomic
-    def get_location_list_remainder(self, location_list):
+    def get_location_list_remainder(self, location_group_list,container_code):
         """
         获取可用库位的c_number列表
         :param location_list: 库位对象列表
         :return: 可用库位编号列表
         """
-        if not location_list:
+        if not location_group_list:
             return None
         min_c_number=1000
         min_c_number_index=1000
-
-        for location in location_list:
-            if location.status != 'available':
-                continue
-            if int(location.c_number)<min_c_number:
-                min_c_number=int(location.c_number)
-                min_c_number_index=location_list.index(location)
-        if min_c_number_index==1000:
-            return None
-        else:  
-            return min_c_number_index
-    @transaction.atomic
-    def get_location_by_type_remainder(self, batch, layer):
-        """
-        根据库位类型获取库位
-        :param batch: 批次号
-        :param layer: 层数限制
-        :return: 符合条件的库位列表
-        """
-        # 获取符合条件的库位组并按优先级排序
-        location_groups = LocationGroupModel.objects.filter(
-            current_batch=batch,
-            layer=layer,
-        ).first()
-
-        if not location_groups:
-            return None
-        # 合并所有库位组中的库位
-        locations = []
-        locations.extend(location_groups.location_items.all())  # 假设location_items是关联字段
-
-        return locations if locations else None
-    @transaction.atomic
-    def get_location_by_type(self, location_type_list, start_location, layer):
-        """
-        第一次入库,根据库位类型获取库位
-        :param location_type_list: 库位类型列表
-        :param start_location: 起始位置(决定优先级排序方式)
-        :param layer: 层数限制
-        :return: 符合条件的库位列表
-        """
-        # 获取符合条件的库位组并按优先级排序
-        location_groups = LocationGroupModel.objects.filter(
-            group_type__in=location_type_list,
-            layer=layer,
-            status='available'
+         
+        current_task = self.get_current_finish_task(container_code)
+        print(f"当前已完成任务: {current_task}")
+        # 按压力排序
+        sorted_pressure = sorted(
+            [(0, current_task[0]), (1, current_task[1]), (2, current_task[2])],
+            key=lambda x: (-x[1], x[0])
         )
-
-        # 根据起始位置选择排序字段
-        if start_location == 'in1':
-            ordered_groups = location_groups.order_by('left_priority')
-        elif start_location == 'in2':
-            ordered_groups = location_groups.order_by('right_priority')
-        else:
-            ordered_groups = location_groups.none()
-
-        locations = []
-        locations.extend(ordered_groups.first().location_items.all()) 
-        return locations if locations else None
-       
+        # 交换第一和第二个元素的位置
+        sorted_pressure[0], sorted_pressure[1] = sorted_pressure[1], sorted_pressure[0]
+        print(f"任务排序: {sorted_pressure}")
+        print(f"当前选择:{sorted_pressure[0][0]+1}")
+        location_type_dict = json.loads(self.divide_solution_by_layer(location_group_list))
+        print(f"库位类型分配方案: {location_type_dict}")
+   
+        for layer, _ in sorted_pressure:
+            if not location_type_dict.get(str(layer+1)):
+                continue
+            print(f"当前层: {layer+1}")
+            print(f"当前层库位组: {location_type_dict[str(layer+1)].keys()}")
+            for group_id in location_type_dict[str(layer+1)].keys():
+                location_group = LocationGroupModel.objects.filter(
+                    id=group_id,
+                ).first()
+                if not location_group:
+                    continue
+                location_list = location_group.location_items.filter(
+                    status='available'
+                ).all().order_by('c_number')
+                if not location_list:
+                    print(f"当前层库位组 {location_group.group_code} 可用库位: None")
+                    continue
+               # 提取所有库位的 c_number
+                c_numbers = [loc.c_number for loc in location_list]
+                print(f"当前层库位组 {location_group.group_code} 可用库位: {c_numbers}")
+                return location_list[0]
+      
     def get_location_type(self, container_code):
         """
         智能库位分配核心算法
@@ -617,7 +594,7 @@ class LocationAllocation:
             current_pressure = self.get_current_pressure()
 
             # 测试参数
-            # total_pallets = 3
+            total_pallets = 30
             # layer_capacity = [{'T1': 29, 'T2': 14, 'S4': 10, 'T4': 27, 'T5': 27}, {'T1': 0, 'T2': 0, 'S4': 0, 'T4': 0, 'T5': 21}, {'T1': 29, 'T2': 14, 'S4': 10, 'T4': 27, 'T5': 27}]
             # current_pressure = [1,0,0]
             print(f"[1]托盘数目: {total_pallets}")
@@ -627,10 +604,10 @@ class LocationAllocation:
             # 定义库位容量表
             LOCATION_CAPACITY = {'T1':1, 'T2':2, 'S4':4, 'T4':4, 'T5':5}
             
-            def allocate(remain, path, pressure,layer_capacity_state, depth=0):
+            def allocate(remain, path, pressure,real_pressure,layer_capacity_state, depth=0):
                 # 终止条件
                 if remain <= 0:
-                    return [path,pressure]
+                    return [path,real_pressure]
                 # 深拷贝当前层容量状态
                 new_layer_capacity = copy.deepcopy(layer_capacity_state)
                 # print(f"[2]当前剩余: {new_layer_capacity}")
@@ -669,11 +646,15 @@ class LocationAllocation:
                         if effective_cap <= remain:
                             new_remain = remain - effective_cap
                             new_pressure = pressure.copy()
-                            new_pressure[layer] += effective_cap  # 按实际存放数计算压力
+                            for i in range(0, 3):
+                                new_pressure[i] -=1 if new_pressure[i] > 0 else 0
+                            new_pressure[layer] += effective_cap  # 按实际存放数计算压力,此时别的楼层压力可能降下来了
+                            real_pressure[layer] += effective_cap  # 实际压力
                             result = allocate(
                                 new_remain, 
                                 path + [f"{layer+1}_{loc_type}"],
                                 new_pressure,
+                                real_pressure,
                                 updated_capacity,
                                 depth + 1
                             )
@@ -684,7 +665,7 @@ class LocationAllocation:
                 return None
 
             # 执行分配
-            allocation = allocate(total_pallets, [], [current_pressure[0], current_pressure[1],current_pressure[2]], layer_capacity)
+            allocation = allocate(total_pallets, [], [current_pressure[0], current_pressure[1],current_pressure[2]],[current_pressure[0], current_pressure[1],current_pressure[2]], layer_capacity)
             
             if not allocation:
                 logger.error("无法生成有效分配方案")
@@ -695,13 +676,15 @@ class LocationAllocation:
             print(f"[6]分配方案: {allocation_json}")
             solution = alloction_pre(
                 batch_number=batch,
-                layer_pre_type =allocation_json,
-                layer1_pressure=allocation[1][0],
-                layer2_pressure=allocation[1][1],
-                layer3_pressure=allocation[1][2],
+                layer_pre_type =allocation_json
             )
-          
+            solution_pressure = base_location.objects.get(id=1)
+            solution_pressure.layer1_pressure = allocation[1][0]
+            solution_pressure.layer2_pressure = allocation[1][1]
+            solution_pressure.layer3_pressure = allocation[1][2]
+
             solution.save()
+            solution_pressure.save()
 
             return [loc.split('_')[1] for loc in allocation[0]]
 
@@ -737,20 +720,87 @@ class LocationAllocation:
 
     def get_current_pressure(self):
         """获取实时工作压力"""
-        last_solution = alloction_pre.objects.order_by('-id').first()
+        last_solution = base_location.objects.order_by('-id').first()
+        if not last_solution:
+            base_location.objects.create(
+                layer1_pressure=0,
+                layer2_pressure=0,
+                layer3_pressure=0,
+            ).save()
         return [
             last_solution.layer1_pressure if last_solution else 0,
             last_solution.layer2_pressure if last_solution else 0,
             last_solution.layer3_pressure if last_solution else 0,
         ]
+    def get_current_finish_task(self,container):
+        batch = self.get_batch(container) 
+
+        if not batch:
+            return None
+        solution = alloction_pre.objects.filter(batch_number=batch).first()
+        if not solution:
+            return None
+
+        return [solution.layer1_task_finish_number,solution.layer2_task_finish_number,solution.layer3_task_finish_number]
 
     @transaction.atomic
-    def get_location_by_status(self,container_code,start_location,layer):
+    def get_location_by_type(self, location_type_list, start_location, container_code):
+        """
+        根据库位类型获取库位,先根据工作压力找出最空闲的层,看下这层有没有工作,如果有,就从里面找,如果没有,则跳过该层,继续找下一层
+        :param location_type_list: 库位分配方案
+        {
+            "1": {
+                "S4": 1
+            },
+            "2": {},
+            "3": {
+                "T5": 1
+            }
+        }
+        :param start_location: 起始位置(决定优先级排序方式)
+        :return: 符合条件的库位列表
+        """
+        locations = []
+
+        for layer, location_type_dict in location_type_list.items():
+
+            if not location_type_dict:
+                continue
+            # 获取库位类型列表
+            location_type = list(location_type_dict.keys())
+            demand_number = sum(location_type_dict.values())
+            print (f"层{layer} 需求数量: {demand_number}, 库位: {location_type}")                    
+            location_groups = LocationGroupModel.objects.filter(
+                group_type__in=location_type,
+                layer=layer,
+                status='available'
+            )
+            if not location_groups:
+                print(f"层{layer} 无库位")
+            # 根据起始位置选择排序字段
+            if start_location == 'in1':
+                ordered_groups = location_groups.order_by('left_priority')
+            elif start_location == 'in2':
+                ordered_groups = location_groups.order_by('right_priority')
+            else:
+                ordered_groups = location_groups.none()
+
+            number = 0
+            for location_group in ordered_groups:
+                if number >= demand_number:
+                    break
+                locations.append(f"{layer}_{location_group.id}")
+                number += 1
+         
+        return locations if locations else None
+
+
+    @transaction.atomic
+    def get_location_by_status(self,container_code,start_location):
         """
         根据库位状态获取库位
         :param location_type: 库位类型
         :param start_location: 起始库位 if in1 优先考虑left_priority, if in2 优先考虑right_priority 就是获取库位组列表之后进行排序
-        :param layer: 层数 限定层数
         :return: 库位列表
         """
         # 1. 获取批次状态 1 为已组盘 2 为部分入库 3 为全部入库
@@ -759,35 +809,29 @@ class LocationAllocation:
         if status == 1:
             # 2. 获取库位组
             print (f"第一次入库")
-            location_type_list = self.get_location_type(container_code)
-            print(f"库位类型:{location_type_list}")
-            location_list = self.get_location_by_type(location_type_list,start_location,layer)
-            print(f"库位列表:{location_list}")
-            location_min_index = self.get_location_list_remainder(location_list)
-            print(f"库位安排到第{location_min_index+1}个库位:{location_list[location_min_index]}")
-            if not location_list[location_min_index]:
-                # 库位已满,返回None
-                return None
-            else:
+            self.get_location_type(container_code)
+            location_type_list = json.loads(alloction_pre.objects.filter(batch_number=self.get_batch(container_code)).first().layer_pre_type)
+            print(f"库组分配方案:{location_type_list}")
+            location_list = self.get_location_by_type(location_type_list,start_location,container_code)
+            print(f"库组列表:{location_list}")
+            # 预定这些库组
+
+            location_min_value = self.get_location_list_remainder(location_list,container_code)
+            print(f"库位安排到第{location_min_value.c_number}个库位:{location_min_value}")
+            # if not location_list[location_min_index]:
+            #     # 库位已满,返回None
+            #     return None
+            # else:
                 
-                return location_list[location_min_index]
+            #     return location_list[location_min_index]
+            return 1
+      
         elif status == 2:
-            print(f"部分入库")
-            # 2. 获取库位组
-            location_list = self.get_location_by_type_remainder(self.get_batch(container_code),layer)
+            # 3. 获取部分入库库位
+            print (f"部分入库")
+            location_list = self.get_location_by_status_part(container_code,start_location)
             print(f"库位列表:{location_list}")
-            location_min_index = self.get_location_list_remainder(location_list)
-            print(f"库位安排到第{location_min_index+1}个库位:{location_list[location_min_index]}")
-            if not location_list[location_min_index]:
-                # 库位已满,返回None
-                return None
-            else:
-                return location_list[location_min_index]
-        elif status == 3:
-            print(f"全部入库")
-            # 2. 获取库位组
-            location_list = self.get_location_by_type_remainder(self.get_batch(container_code),layer)
-            return location_list
+
             
   
       

+ 3 - 3
data_base/test_allocation.py

@@ -27,13 +27,13 @@ def main():
         # 从正确的应用导入模型
         from bin.views import LocationAllocation
         
-        container_code =["12346", "12345", "1", "2", "7"]
-        # container_code =["1"]
+        # container_code =["12346", "12345", "1", "2", "7"]
+        container_code =["1"]
         allocator = LocationAllocation()  # 创建实例
 
         for code in container_code:  # Iterate through each container code
             print(f"开始生成库位,托盘编码:{code}")
-            location_type = allocator.get_location_type(code)  # 获取库位类型
+            location_type = allocator.get_location_by_status(code,'in1')  # 获取库位类型
             if not location_type:
                 print("❌ 库位类型获取失败,请检查托盘数量")
                 return