flower_mr il y a 18 heures
Parent
commit
e7f08741ae
39 fichiers modifiés avec 2685 ajouts et 69 suppressions
  1. 9 4
      erp/filter.py
  2. 5 2
      erp/urls.py
  3. 198 10
      erp/views.py
  4. 317 0
      logs/boundBill.log
  5. 210 0
      logs/error.log
  6. 1349 0
      logs/server.log
  7. 0 1
      templates/dist/spa/css/10.0776afdc.css
  8. 1 0
      templates/dist/spa/css/10.a5d7d7ca.css
  9. 0 1
      templates/dist/spa/css/23.4a53120f.css
  10. 1 0
      templates/dist/spa/css/23.bdff6d34.css
  11. 0 1
      templates/dist/spa/css/8.07a28878.css
  12. 1 0
      templates/dist/spa/css/8.53dd35ce.css
  13. 1 1
      templates/dist/spa/index.html
  14. 1 0
      templates/dist/spa/js/10.4f174308.js
  15. BIN
      templates/dist/spa/js/10.4f174308.js.gz
  16. 0 1
      templates/dist/spa/js/10.efaa843e.js
  17. BIN
      templates/dist/spa/js/10.efaa843e.js.gz
  18. 1 0
      templates/dist/spa/js/22.7f534dae.js
  19. BIN
      templates/dist/spa/js/22.7f534dae.js.gz
  20. 0 1
      templates/dist/spa/js/22.9a28159a.js
  21. BIN
      templates/dist/spa/js/22.9a28159a.js.gz
  22. 0 1
      templates/dist/spa/js/23.159638d0.js
  23. BIN
      templates/dist/spa/js/23.159638d0.js.gz
  24. 1 0
      templates/dist/spa/js/23.ac5c0d62.js
  25. BIN
      templates/dist/spa/js/23.ac5c0d62.js.gz
  26. 0 1
      templates/dist/spa/js/8.0a90d787.js
  27. BIN
      templates/dist/spa/js/8.0a90d787.js.gz
  28. 1 0
      templates/dist/spa/js/8.9d9149e0.js
  29. BIN
      templates/dist/spa/js/8.9d9149e0.js.gz
  30. 1 0
      templates/dist/spa/js/app.4f2b4b5c.js
  31. BIN
      templates/dist/spa/js/app.4f2b4b5c.js.gz
  32. 0 1
      templates/dist/spa/js/app.f234224b.js
  33. BIN
      templates/dist/spa/js/app.f234224b.js.gz
  34. 2 2
      templates/dist/spa/js/vendor.5f12bb2e.js
  35. BIN
      templates/dist/spa/js/vendor.5f12bb2e.js.gz
  36. 1 1
      templates/src/layouts/MainLayout.vue
  37. 24 0
      templates/src/pages/container/containerlist.vue
  38. 271 23
      templates/src/pages/erp/erpasn.vue
  39. 290 18
      templates/src/pages/erp/erpdn.vue

+ 9 - 4
erp/filter.py

@@ -7,7 +7,7 @@ class OutboundBillFilter(FilterSet):
         fields = {
             "billId": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
             "number": ['exact', 'icontains'],
-            "type": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "type": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range', 'icontains'],
             "date": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
             "department": ['exact', 'icontains'],
             "warehouse": ['exact', 'icontains'],
@@ -17,7 +17,9 @@ class OutboundBillFilter(FilterSet):
             "create_time": ['exact', 'gt', 'gte', 'lt', 'lte', 'range'],
             "update_time": ['exact', 'gt', 'gte', 'lt', 'lte', 'range'],
             "is_delete": ['exact'],
-            "bound_status" : ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range']
+            "bound_status" : ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "audit_status" : ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "save_status" : ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
         }
 
 class InboundBillFilter(FilterSet):
@@ -26,7 +28,8 @@ class InboundBillFilter(FilterSet):
         fields = {
             "billId": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
             "number": ['exact', 'icontains'],
-            "type": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "type": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range', 'icontains'],
+
             "date": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
             "department": ['exact', 'icontains'],
             "warehouse": ['exact', 'icontains'],
@@ -36,7 +39,9 @@ class InboundBillFilter(FilterSet):
             "create_time": ['exact', 'gt', 'gte', 'lt', 'lte', 'range'],
             "update_time": ['exact', 'gt', 'gte', 'lt', 'lte', 'range'],
             "is_delete": ['exact'],
-            "bound_status" : ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range']
+            "bound_status" : ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "audit_status" : ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "save_status" : ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
         }
 
 class MaterialDetailFilter(FilterSet):

+ 5 - 2
erp/urls.py

@@ -8,6 +8,7 @@ urlpatterns = [
     path('updateBatchInfo', views.BatchUpdate.as_view()),
     path('productInfo', views.ProductInfo.as_view()),
     path('generateinbound', views.GenerateInbound.as_view()),
+    path('inboundcheck', views.FindExistingBatch.as_view()),
     path('generateoutbound', views.GenerateOutbound.as_view()),
 
     path('inboundBills/log/', views.InboundBillsLog.as_view({"get": "list"}),name="inboundBillslog"),
@@ -23,12 +24,14 @@ urlpatterns = [
 
     path('inboundBills/', views.InboundBills.as_view({"get": "list"}),name="inboundBills"),
     re_path(r'^inboundBills/(?P<pk>\d+)/$', views.InboundBills.as_view({
-        'get': 'retrieve'
+        'get': 'retrieve',
+        'delete': 'destroy',
     }), name="inboundBills_1"),
 
     path('outboundBills/', views.OutboundBills.as_view({"get": "list"}),name="outboutBills"),
     re_path(r'^outboundBills/(?P<pk>\d+)/$', views.OutboundBills.as_view({
-        'get': 'retrieve'
+        'get': 'retrieve',
+        'delete': 'destroy',
     }), name="outboundBills_1"),
 
     path('materials/', views.Materials.as_view({"get": "list"}),name="Materials"),

+ 198 - 10
erp/views.py

@@ -203,6 +203,38 @@ class InboundApplyCreate(APIView):
             return False,error_details
         return True,None
         
+    def audit_save_status(self, bound_bill_type,base_type):
+        # 根据不同入库单类型和不同出入库类型,返回审核状态和保存状态
+        # bound_bill_type:表示不同出入库类型 :1(生产入库申请-生产汇报单)2(采购入库申请-收料通知单) 3(其他入库)4(调拨入库) 1(销售出库申请-发货通知单) 2(生产领料)3(其他出库) 
+        # 1,1 生产入库-> 0,9 (0为未审核,9为无需保存)
+        # 2,1 采购入库-> 0,0 (0为未审核,0为未保存)
+        # 3,1 其他入库-> 0,9 (0为未审核,9为无需保存)
+        # 4,1 调拨入库-> 0,9 (0为未审核,9为无需保存)
+
+        # 1,2 销售出库-> 9,0 (9为无需审核,0为未保存)
+        # 2,2 生产领料-> 0,9 (0为未审核,9为无需保存)
+        # 3,2 其他出库-> 0,9 (0为未审核,9为无需保存)
+
+        # base_type:表示不同入库单类型 1 为入库 2为出库
+        if base_type == 1:  # 入库
+            if bound_bill_type == 1:  # 生产入库
+                return 0, 9
+            elif bound_bill_type == 2:  # 采购入库
+                return 0, 0
+            elif bound_bill_type == 3:  # 其他入库
+                return 0, 9
+            elif bound_bill_type == 4:  # 调拨入库
+                return 0, 9
+        else:  # 出库
+            if bound_bill_type == 1:  # 销售出库
+                return 9, 0
+            elif bound_bill_type == 2:  # 生产领料
+                return 0, 9
+            elif bound_bill_type == 3:  # 其他出库
+                return 0, 9
+        return 0, 0
+
+
     def save_or_update_inbound_bill(self, serializer):
         """保存或更新入库单"""
         # 保存或更新入库单
@@ -219,7 +251,9 @@ class InboundApplyCreate(APIView):
             if bound_bill.type != 1:
                 bound_bill.erp_audit_id = bound_bill.number
             bound_bill.erp_save_id = bound_bill.billId
+            bound_bill.audit_status, bound_bill.save_status = self.audit_save_status(bound_bill.type,1)
             bound_bill.update_time = timezone.now()
+            bound_bill.is_delete = False 
             bound_bill.save()
 
             InboundBillOperateLog.objects.create(
@@ -228,6 +262,7 @@ class InboundApplyCreate(APIView):
                 log_content = f"更新入库单{bound_bill.number}信息",
             )
         except InboundBill.DoesNotExist:
+            audit_status, save_status = self.audit_save_status(serializer.validated_data['type'], 1)
             bound_bill = InboundBill.objects.create(
                 billId=serializer.validated_data['billId'],
                 number=serializer.validated_data['number'],
@@ -238,8 +273,9 @@ class InboundApplyCreate(APIView):
                 creater=serializer.validated_data['creater'],
                 note=(serializer.validated_data['note'] if 'note' in serializer.validated_data else ''),
                 totalCount=serializer.validated_data['totalCount'],
-               
                 erp_save_id = serializer.validated_data['billId'],
+                audit_status  = audit_status,
+                save_status = save_status,
                 create_time=timezone.now(),
                 update_time=timezone.now()
             )
@@ -270,6 +306,7 @@ class InboundApplyCreate(APIView):
                 material_detail.goods_unit = item['goods_unit']
                 material_detail.note = (item['note'] if 'note' in item else '')
                 material_detail.update_time = timezone.now()
+                material_detail.is_delete = False 
                 material_detail.save()
             except MaterialDetail.DoesNotExist:
                 material_detail = MaterialDetail.objects.create(
@@ -511,9 +548,82 @@ class GenerateInbound(APIView):
             openid='ERP',
             relate_bill=bill_obj 
         )
+    def handle_exception(self, exc):
+        """统一异常处理"""
+        if isinstance(exc, InboundBill.DoesNotExist):
+            return Response({"error": "原始单据不存在或已被删除"}, status=status.HTTP_404_NOT_FOUND)
+        elif "重复" in str(exc):
+            return Response({"error": str(exc)}, status=status.HTTP_409_CONFLICT)
+        return super().handle_exception(exc)
 
+class FindExistingBatch(APIView):
+    """
+    预查询是否存在可关联的离线批次
+    匹配策略:
+    1. 标准化批次号完全匹配
+    2. 相同物料代码
+    3. 批次未关联其他物料
+    4. 批次状态有效
+    """
 
 
+    def post(self, request):
+        """
+        预查询是否存在可关联的离线批次
+        匹配策略:
+        1. 标准化批次号完全匹配
+        2. 相同物料代码
+        3. 批次未关联其他物料
+        4. 批次状态有效
+        """
+        # 标准化批次号处理
+        try:
+            bill_id = request.data.get('billId')
+            InboundBill_obj = InboundBill.objects.get(billId=bill_id, is_delete=False)
+            if not InboundBill_obj:
+                raise InboundBill.DoesNotExist(f"原始单据不存在或已被删除")
+            MaterialDetail_obj_all = MaterialDetail.objects.filter(bound_billId=InboundBill_obj, is_delete=False).all()
+            if not MaterialDetail_obj_all:
+                raise Exception("入库单没有有效物料明细")
+            # 拆分生产批次(物料代码-批次号)
+            material_map = {}
+            for material in MaterialDetail_obj_all:
+                parts = material.production_batch.split('-')
+                if len(parts) < 2:
+                    raise ValueError(f"无效的生产批次格式: {material.production_batch}")
+                    
+                material_goods_code = parts[0]
+                batch_str = parts[1]
+                
+                # 标准化批次号处理
+                if len(batch_str) == 7:  # 2508001 格式
+                    # 添加"20"前缀转为9位格式: 202508001
+                    standardized_batch = "20" + batch_str
+                elif len(batch_str) == 9:  # 202508001 格式
+                    standardized_batch = batch_str
+                else:
+                    raise ValueError(f"无效的批次号长度: {batch_str}")
+                    
+                # 创建规范化的bound_number(物料代码-标准批次号)
+                bound_number = f"{material_goods_code}-{standardized_batch}"
+                material.material_goods_code = material_goods_code
+                material.material_batch_order = standardized_batch
+                material.save(update_fields=['material_goods_code','material_batch_order'])
+                if BoundBatchModel.objects.filter(bound_number=bound_number, is_delete=False).exists():
+                    material_map[bound_number] = True
+                else:
+                    material_map[bound_number] = False
+            return_data= material_map
+            return Response({
+                "code": 200,
+                "data": return_data
+            }, status=status.HTTP_200_OK)
+
+        except (IndexError, ValueError) as e:
+            raise Exception(f"物料批次处理错误: {e}")
+
+       
+
     def handle_exception(self, exc):
         """统一异常处理"""
         if isinstance(exc, InboundBill.DoesNotExist):
@@ -894,7 +1004,38 @@ class OutboundApplyCreate(APIView):
         if error_details:
             return False,error_details
         return True,None
-        
+
+    def audit_save_status(self, bound_bill_type,base_type):
+        # 根据不同入库单类型和不同出入库类型,返回审核状态和保存状态
+        # bound_bill_type:表示不同出入库类型 :1(生产入库申请-生产汇报单)2(采购入库申请-收料通知单) 3(其他入库)4(调拨入库) 1(销售出库申请-发货通知单) 2(生产领料)3(其他出库) 
+        # 1,1 生产入库-> 0,9 (0为未审核,9为无需保存)
+        # 2,1 采购入库-> 0,0 (0为未审核,0为未保存)
+        # 3,1 其他入库-> 0,9 (0为未审核,9为无需保存)
+        # 4,1 调拨入库-> 0,9 (0为未审核,9为无需保存)
+
+        # 1,2 销售出库-> 9,0 (9为无需审核,0为未保存)
+        # 2,2 生产领料-> 0,9 (0为未审核,9为无需保存)
+        # 3,2 其他出库-> 0,9 (0为未审核,9为无需保存)
+
+        # base_type:表示不同入库单类型 1 为入库 2为出库
+        if base_type == 1:  # 入库
+            if bound_bill_type == 1:  # 生产入库
+                return 0, 9
+            elif bound_bill_type == 2:  # 采购入库
+                return 0, 0
+            elif bound_bill_type == 3:  # 其他入库
+                return 0, 9
+            elif bound_bill_type == 4:  # 调拨入库
+                return 0, 9
+        else:  # 出库
+            if bound_bill_type == 1:  # 销售出库
+                return 9, 0
+            elif bound_bill_type == 2:  # 生产领料
+                return 0, 9
+            elif bound_bill_type == 3:  # 其他出库
+                return 0, 9
+        return 0, 0
+
     def save_or_update_outbound_bill(self, serializer):
         """保存或更新出库单"""
         try:
@@ -910,8 +1051,10 @@ class OutboundApplyCreate(APIView):
            
             bound_bill.erp_audit_id = bound_bill.number
             bound_bill.erp_save_id = bound_bill.billId
+            bound_bill.audit_status ,bound_bill.save_status = self.audit_save_status(bound_bill.type,2)
 
             bound_bill.update_time = timezone.now()
+            bound_bill.is_delete = False 
             bound_bill.save()
             OutboundBillOperateLog.objects.create(
                 billId=bound_bill,
@@ -921,6 +1064,7 @@ class OutboundApplyCreate(APIView):
 
 
         except OutboundBill.DoesNotExist:
+            audit_status, save_status = self.audit_save_status(serializer.validated_data['type'], 2)
             bound_bill = OutboundBill.objects.create(
                 billId=serializer.validated_data['billId'],
                 number=serializer.validated_data['number'],
@@ -933,6 +1077,9 @@ class OutboundApplyCreate(APIView):
                 totalCount=serializer.validated_data['totalCount'],
                 erp_audit_id = serializer.validated_data['number'],
                 erp_save_id = serializer.validated_data['billId'],
+
+                audit_status  = audit_status,
+                save_status = save_status,
                 create_time=timezone.now(),
                 update_time=timezone.now()
             )
@@ -963,6 +1110,7 @@ class OutboundApplyCreate(APIView):
                 material_detail.goods_unit = item['goods_unit']
                 material_detail.note = (item['note'] if 'note' in item else '')
                 material_detail.update_time = timezone.now()
+                material_detail.is_delete = False
                 material_detail.save()
             except OutMaterialDetail.DoesNotExist:
                 Material_entryIds = MaterialDetail.objects.filter(
@@ -1219,7 +1367,8 @@ class AccessToken(APIView):
     def get_token(cls):
         try:
             """获取access_token"""
-            url = "https://okyy.test.kdgalaxy.com/kapi/oauth2/getToken"
+            # url = "https://okyy.test.kdgalaxy.com/kapi/oauth2/getToken" # 测试环境
+            url = "https://okyy.kdgalaxy.com/kapi/oauth2/getToken"
             data = {
                 "client_id" : "WMS",
                 "client_secret" : "1Ca~2Tu-3Fx$3Rg@",
@@ -1326,7 +1475,8 @@ class ProductionInboundAuditSync(ERPSyncBase):
     erp_id_field = 'erp_audit_id'
     # 请求地址
     def get_erp_endpoint(self):
-        return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_mdc_mftmanuinbill/audit"
+        # return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_mdc_mftmanuinbill/audit"
+        return "https://okyy.kdgalaxy.com/kapi/v2/l772/im/im_mdc_mftmanuinbill/audit"
     # 请求参数
         #     {
     # 	"data":{
@@ -1358,7 +1508,8 @@ class PurchaseInboundAuditSync(ERPSyncBase):
     erp_id_field = 'erp_audit_id'
     # 请求地址
     def get_erp_endpoint(self):
-        return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_purreceivebill/audit"
+        # return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_purreceivebill/audit"
+        return "https://okyy.kdgalaxy.com/kapi/v2/l772/im/im_purreceivebill/audit"
     # 请求参数
         #     {
     # 	"data":{
@@ -1390,7 +1541,8 @@ class OtherInboundAuditSync(ERPSyncBase):
     erp_id_field = 'erp_audit_id'
     # 请求地址
     def get_erp_endpoint(self):
-        return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_otherinbill/audit"
+        # return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_otherinbill/audit"
+        return "https://okyy.kdgalaxy.com/kapi/v2/l772/im/im_otherinbill/audit"
     # 请求参数
         #     {
     # 	"data":{
@@ -1422,7 +1574,8 @@ class TransferInboundAuditSync(ERPSyncBase):
     erp_id_field = 'erp_audit_id'
     # 请求地址
     def get_erp_endpoint(self):
-        return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_transdirbill/audit"
+        # return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_transdirbill/audit"
+        return "https://okyy.kdgalaxy.com/kapi/v2/l772/im/im_transdirbill/audit"
 
     # 请求参数
         #     {
@@ -1487,7 +1640,8 @@ class ProductionOutboundAuditSync(ERPSyncBase):
     erp_id_field = 'erp_audit_id'
     # 请求地址
     def get_erp_endpoint(self):
-        return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_mdc_mftproorder/audit"
+        # return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_mdc_mftproorder/audit"
+        return "https://okyy.kdgalaxy.com/kapi/v2/l772/im/im_mdc_mftproorder/audit"
     # 请求参数
         #     {
     # 	"data":{
@@ -1520,7 +1674,8 @@ class PurchaseInboundSaveSync(ERPSyncBase):
     erp_id_field = 'erp_save_id'
     
     def get_erp_endpoint(self):
-        return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_purinbill/save"
+        # return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_purinbill/save"
+        return "https://okyy.kdgalaxy.com/kapi/v2/l772/im/im_purinbill/save"
         
     def build_erp_payload(self):
 
@@ -1559,7 +1714,8 @@ class SaleOutboundSaveSync(ERPSyncBase):
     erp_id_field = 'erp_save_id'
     
     def get_erp_endpoint(self):
-        return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_saloutbill/save"
+        # return "https://okyy.test.kdgalaxy.com/kapi/v2/l772/im/im_saloutbill/save"
+        return "https://okyy.kdgalaxy.com/kapi/v2/l772/im/im_saloutbill/save"
         
     def build_erp_payload(self):
 
@@ -1791,6 +1947,23 @@ class InboundBills(viewsets.ModelViewSet):
             return_data['bill_type'] = bill_obj.type
         return Response(return_data,status=status.HTTP_200_OK)
     
+    def destroy(self, request, pk):
+
+        qs = self.get_object()
+        qs.is_delete = True
+        
+        MaterialDetail.objects.filter(bound_billId=qs).update(is_delete=True)
+        qs.save()
+
+        # import datetime
+        # qs.save()
+        # qs.billId = f"404{qs.billId}{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
+        # qs.number = f"deleted_{qs.number}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
+        # qs.save()
+        return Response({'message': '删除成功'}, status=status.HTTP_200_OK)
+
+        
+    
 """前端视图类·ERP出库"""
 class OutboundBills(viewsets.ModelViewSet):
     """
@@ -1844,6 +2017,21 @@ class OutboundBills(viewsets.ModelViewSet):
             return_data['bill_status'] = bill_obj.bound_status
             return_data['bill_type'] = bill_obj.type
         return Response(return_data,status=status.HTTP_200_OK)
+    
+    def destroy(self, request, pk):
+
+        qs = self.get_object()
+        qs.is_delete = True
+        
+        OutMaterialDetail.objects.filter(bound_billId=qs).update(is_delete=True)
+        qs.save()
+
+        # import datetime
+        # qs.save()
+        # qs.billId = f"404{qs.billId}{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
+        # qs.number = f"deleted_{qs.number}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
+        # qs.save()
+        return Response({'message': '删除成功'}, status=status.HTTP_200_OK)
         
 class Materials(viewsets.ModelViewSet):
     """

Fichier diff supprimé car celui-ci est trop grand
+ 317 - 0
logs/boundBill.log


+ 210 - 0
logs/error.log

@@ -12472,3 +12472,213 @@ django.db.utils.OperationalError: database is locked
 [2025-06-13 11:14:32,305][django.server.log_message():187] [ERROR] "POST /container/out_task/ HTTP/1.1" 500 46
 [2025-06-13 11:14:48,421][django.request.log_response():241] [ERROR] Internal Server Error: /container/container_wcs/
 [2025-06-13 11:14:48,423][django.server.log_message():187] [ERROR] "PUT /container/container_wcs/ HTTP/1.1" 500 60
+[2025-06-23 00:19:14,304][django.request.log_response():241] [ERROR] Internal Server Error: /wms/inboundBills/2/
+Traceback (most recent call last):
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 472, in thread_handler
+    raise exc_info[1]
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\exception.py", line 42, in inner
+    response = await get_response(request)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\base.py", line 253, in _get_response_async
+    response = await wrapped_callback(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 435, in __call__
+    ret = await asyncio.wait_for(future, timeout=None)
+  File "D:\language\python38\lib\asyncio\tasks.py", line 455, in wait_for
+    return await fut
+  File "D:\language\python38\lib\concurrent\futures\thread.py", line 57, in run
+    result = self.fn(*self.args, **self.kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 476, in thread_handler
+    return func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\viewsets.py", line 125, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 506, in dispatch
+    response = handler(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.\erp\views.py", line 1874, in destroy
+    qs.billId = uuid.uuid4()
+NameError: name 'uuid' is not defined
+[2025-06-23 00:20:30,891][django.request.log_response():241] [ERROR] Internal Server Error: /wms/inboundBills/2/
+Traceback (most recent call last):
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 472, in thread_handler
+    raise exc_info[1]
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\exception.py", line 42, in inner
+    response = await get_response(request)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\base.py", line 253, in _get_response_async
+    response = await wrapped_callback(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 435, in __call__
+    ret = await asyncio.wait_for(future, timeout=None)
+  File "D:\language\python38\lib\asyncio\tasks.py", line 455, in wait_for
+    return await fut
+  File "D:\language\python38\lib\concurrent\futures\thread.py", line 57, in run
+    result = self.fn(*self.args, **self.kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 476, in thread_handler
+    return func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\viewsets.py", line 125, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 506, in dispatch
+    response = handler(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.\erp\views.py", line 1877, in destroy
+    MaterialDetail.objects.filter(bound_billId=qs.id).update(bound_billId=qs.billId)
+AttributeError: 'InboundBill' object has no attribute 'id'
+[2025-06-23 00:21:31,972][django.request.log_response():241] [ERROR] Internal Server Error: /wms/inboundBills/2/
+Traceback (most recent call last):
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 115, in debug_sql
+    yield
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 103, in execute
+    return super().execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 67, in execute
+    return self._execute_with_wrappers(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 80, in _execute_with_wrappers
+    return executor(sql, params, many, context)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
+    return self.cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 357, in execute
+    return Database.Cursor.execute(self, query, params)
+OverflowError: Python int too large to convert to SQLite INTEGER
+
+During handling of the above exception, another exception occurred:
+
+Traceback (most recent call last):
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 472, in thread_handler
+    raise exc_info[1]
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\exception.py", line 42, in inner
+    response = await get_response(request)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\base.py", line 253, in _get_response_async
+    response = await wrapped_callback(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 435, in __call__
+    ret = await asyncio.wait_for(future, timeout=None)
+  File "D:\language\python38\lib\asyncio\tasks.py", line 455, in wait_for
+    return await fut
+  File "D:\language\python38\lib\concurrent\futures\thread.py", line 57, in run
+    result = self.fn(*self.args, **self.kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\asgiref\sync.py", line 476, in thread_handler
+    return func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\viewsets.py", line 125, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 506, in dispatch
+    response = handler(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.\erp\views.py", line 1878, in destroy
+    qs.save()
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\base.py", line 812, in save
+    self.save_base(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\base.py", line 863, in save_base
+    updated = self._save_table(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\base.py", line 976, in _save_table
+    updated = self._do_update(
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\base.py", line 1040, in _do_update
+    return filtered._update(values) > 0
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\query.py", line 1215, in _update
+    return query.get_compiler(self.db).execute_sql(CURSOR)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\sql\compiler.py", line 1822, in execute_sql
+    cursor = super().execute_sql(result_type)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\models\sql\compiler.py", line 1398, in execute_sql
+    cursor.execute(sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 103, in execute
+    return super().execute(sql, params)
+  File "D:\language\python38\lib\contextlib.py", line 131, in __exit__
+    self.gen.throw(type, value, traceback)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\utils.py", line 120, in debug_sql
+    sql = self.db.ops.last_executed_query(self.cursor, sql, params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\sqlite3\operations.py", line 178, in last_executed_query
+    params = self._quote_params_for_last_executed_query(params)
+  File "D:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\db\backends\sqlite3\operations.py", line 165, in _quote_params_for_last_executed_query
+    return cursor.execute(sql, params).fetchone()
+OverflowError: Python int too large to convert to SQLite INTEGER
+[2025-06-23 00:41:15,992][django.request.log_response():241] [ERROR] Internal Server Error: /wms/inboundBills/2/
+Traceback (most recent call last):
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
+    response = get_response(request)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
+    response = wrapped_callback(request, *callback_args, **callback_kwargs)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\viewsets.py", line 125, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 506, in dispatch
+    response = handler(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\erp\views.py", line 1879, in destroy
+    qs.billId = uuid.uuid4() >> 128
+TypeError: unsupported operand type(s) for >>: 'UUID' and 'int'
+[2025-06-23 00:41:15,998][django.server.log_message():187] [ERROR] "DELETE /wms/inboundBills/2/ HTTP/1.1" 500 111214
+[2025-06-23 02:04:08,718][django.request.log_response():241] [ERROR] Internal Server Error: /wms/inboundcheck
+Traceback (most recent call last):
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
+    response = get_response(request)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
+    response = wrapped_callback(request, *callback_args, **callback_kwargs)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\generic\base.py", line 103, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "D:\Document\code\vue\greater_wms\erp\views.py", line 631, in handle_exception
+    return super().handle_exception(exc)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 506, in dispatch
+    response = handler(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\erp\views.py", line 585, in post
+    raise Exception("入库单没有有效物料明细")
+Exception: 入库单没有有效物料明细
+[2025-06-23 02:04:08,727][django.server.log_message():187] [ERROR] "POST /wms/inboundcheck HTTP/1.1" 500 114393
+[2025-06-23 02:06:07,926][django.request.log_response():241] [ERROR] Internal Server Error: /wms/inboundcheck
+Traceback (most recent call last):
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
+    response = get_response(request)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
+    response = wrapped_callback(request, *callback_args, **callback_kwargs)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\django\views\generic\base.py", line 103, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "D:\Document\code\vue\greater_wms\erp\views.py", line 631, in handle_exception
+    return super().handle_exception(exc)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "d:\Document\code\vue\greater_wms\.venv\lib\site-packages\rest_framework\views.py", line 506, in dispatch
+    response = handler(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\erp\views.py", line 585, in post
+    raise Exception("入库单没有有效物料明细")
+Exception: 入库单没有有效物料明细
+[2025-06-23 02:06:07,934][django.server.log_message():187] [ERROR] "POST /wms/inboundcheck HTTP/1.1" 500 114815
+[2025-06-23 02:54:12,310][django.request.log_response():241] [ERROR] Internal Server Error: /wms/createOutboundApply
+[2025-06-23 02:54:12,311][django.server.log_message():187] [ERROR] "POST /wms/createOutboundApply HTTP/1.1" 500 138
+[2025-06-23 02:54:36,466][django.request.log_response():241] [ERROR] Internal Server Error: /wms/createOutboundApply
+[2025-06-23 02:54:36,468][django.server.log_message():187] [ERROR] "POST /wms/createOutboundApply HTTP/1.1" 500 138
+[2025-06-23 02:56:25,502][django.request.log_response():241] [ERROR] Internal Server Error: /wms/createOutboundApply
+[2025-06-23 02:56:25,505][django.server.log_message():187] [ERROR] "POST /wms/createOutboundApply HTTP/1.1" 500 138

Fichier diff supprimé car celui-ci est trop grand
+ 1349 - 0
logs/server.log


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1
templates/dist/spa/css/10.0776afdc.css


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
templates/dist/spa/css/10.a5d7d7ca.css


+ 0 - 1
templates/dist/spa/css/23.4a53120f.css

@@ -1 +0,0 @@
-.q-date__calendar-item--selected[data-v-caa3275a]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-caa3275a]{background-color:rgba(25,118,210,0.1)}

+ 1 - 0
templates/dist/spa/css/23.bdff6d34.css

@@ -0,0 +1 @@
+.q-date__calendar-item--selected[data-v-7fe0b347]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-7fe0b347]{background-color:rgba(25,118,210,0.1)}

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1
templates/dist/spa/css/8.07a28878.css


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
templates/dist/spa/css/8.53dd35ce.css


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
templates/dist/spa/index.html


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
templates/dist/spa/js/10.4f174308.js


BIN
templates/dist/spa/js/10.4f174308.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1
templates/dist/spa/js/10.efaa843e.js


BIN
templates/dist/spa/js/10.efaa843e.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
templates/dist/spa/js/22.7f534dae.js


BIN
templates/dist/spa/js/22.7f534dae.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1
templates/dist/spa/js/22.9a28159a.js


BIN
templates/dist/spa/js/22.9a28159a.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1
templates/dist/spa/js/23.159638d0.js


BIN
templates/dist/spa/js/23.159638d0.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
templates/dist/spa/js/23.ac5c0d62.js


BIN
templates/dist/spa/js/23.ac5c0d62.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1
templates/dist/spa/js/8.0a90d787.js


BIN
templates/dist/spa/js/8.0a90d787.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
templates/dist/spa/js/8.9d9149e0.js


BIN
templates/dist/spa/js/8.9d9149e0.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 0
templates/dist/spa/js/app.4f2b4b5c.js


BIN
templates/dist/spa/js/app.4f2b4b5c.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1
templates/dist/spa/js/app.f234224b.js


BIN
templates/dist/spa/js/app.f234224b.js.gz


Fichier diff supprimé car celui-ci est trop grand
+ 2 - 2
templates/dist/spa/js/vendor.5f12bb2e.js


BIN
templates/dist/spa/js/vendor.5f12bb2e.js.gz


+ 1 - 1
templates/src/layouts/MainLayout.vue

@@ -988,7 +988,7 @@ export default {
 
     _this.timer = setInterval(() => {
       _this.handleTimer();
-    }, 10000);
+    }, 100000);
   },
   // 修改时间 :10000
   updated () {},

+ 24 - 0
templates/src/pages/container/containerlist.vue

@@ -137,6 +137,24 @@
               }}</q-td>
             </template>
 
+                        <template v-if="props.row.id === editid">
+              <q-td key="target_location" :props="props">
+                <q-input
+                  dense
+                  outlined
+                  square
+                  v-model="editFormData.target_location"
+                  :label="'目标位置'"
+                  :rules="[(val) => (val && val.length > 0) || error2]"
+                />
+              </q-td>
+            </template>
+            <template v-else-if="props.row.id !== editid">
+              <q-td key="target_location" :props="props">{{
+                props.row.target_location
+              }}</q-td>
+            </template>
+
             <template v-if="props.row.id === editid">
               <q-td key="status" :props="props">
                 <q-input
@@ -261,6 +279,12 @@ export default {
           field: 'current_location',
           align: 'center'
         },
+        {
+          name: 'target_location',
+          label: '目标位置',
+          field: 'target_location',
+          align: 'center'
+        },
         { name: 'status', label: '托盘状态', field: 'status', align: 'center' },
         {
           name: 'last_operation',

+ 271 - 23
templates/src/pages/erp/erpasn.vue

@@ -16,6 +16,43 @@
         flat
         bordered
       >
+        <template v-slot:header-cell="props">
+          <q-th :props="props" @dblclick="handleHeaderDblClick(props.col)">
+            <!-- 为特定列添加下拉选择器 -->
+            <template
+              v-if="
+                [
+                  'type',
+                  'audit_status',
+                  'save_status',
+                  'bound_status',
+                  'department',
+                ].includes(props.col.name)
+              "
+            >
+              <q-select
+                dense
+                outlined
+                v-model="filterModels[props.col.name]"
+                :options="getFilterOptions(props.col.name)"
+                option-label="label"
+                option-value="value"
+                emit-value
+                map-options
+                clearable
+                @input="handleFilterChange"
+                style="min-width: 120px"
+              >
+                <template v-slot:prepend>
+                  <span class="text-caption">{{ props.col.label }}</span>
+                </template>
+              </q-select>
+            </template>
+            <template v-else>
+              {{ props.col.label }}
+            </template>
+          </q-th>
+        </template>
         <template v-slot:top>
           <q-btn-group push>
             <q-btn :label="$t('refresh')" icon="refresh" @click="reFresh()">
@@ -154,18 +191,30 @@
                 }}</q-td
               >
             </template>
-            
+
             <template v-if="props.row.id === editid">
-              <q-td key="audit_status" :props="props">{{ props.row.audit_status }}</q-td>
+              <q-td key="audit_status" :props="props">{{
+                audit_status_name_map[props.row.audit_status] ||
+                props.row.audit_status
+              }}</q-td>
             </template>
             <template v-else-if="props.row.id !== editid">
-              <q-td key="audit_status" :props="props">{{ props.row.audit_status }}</q-td>
+              <q-td key="audit_status" :props="props">{{
+                audit_status_name_map[props.row.audit_status] ||
+                props.row.audit_status
+              }}</q-td>
             </template>
             <template v-if="props.row.id === editid">
-              <q-td key="save_status" :props="props">{{ props.row.save_status }}</q-td>
+              <q-td key="save_status" :props="props">{{
+                save_status_name_map[props.row.save_status] ||
+                props.row.save_status
+              }}</q-td>
             </template>
             <template v-else-if="props.row.id !== editid">
-              <q-td key="save_status" :props="props">{{ props.row.save_status }}</q-td>
+              <q-td key="save_status" :props="props">{{
+                save_status_name_map[props.row.save_status] ||
+                props.row.save_status
+              }}</q-td>
             </template>
 
             <template v-if="props.row.id === editid">
@@ -225,6 +274,20 @@
                     >单据无误</q-tooltip
                   >
                 </q-btn>
+                <q-btn
+                  round
+                  flat
+                  push
+                  color="deep-purple"
+                  icon="delete"
+                  @click="delete_data(props.row)"
+                >
+                  <q-tooltip
+                    content-class="bg-amber text-black shadow-4"
+                    :offset="[10, 10]"
+                    >{{ $t("delete") }}</q-tooltip
+                  >
+                </q-btn>
               </q-td>
             </template>
             <template v-else-if="editMode">
@@ -568,6 +631,16 @@ export default {
   name: 'Pageasnlist',
   data () {
     return {
+      // 新增:过滤模型
+      filterModels: {
+        type: null,
+        audit_status: null,
+        save_status: null,
+        bound_status: null,
+        department: null
+      },
+      activeSearchField: '', // 当前激活的搜索字段
+      activeSearchLabel: '', // 当前激活的搜索字段的标签
       createDate2: '',
       date_range: '',
       proxyDate: '',
@@ -602,12 +675,24 @@ export default {
       bound_desc_map: [],
       bound_department_list: [],
       bound_department_map: [],
+      audit_status_name_map: {
+        0: '待审核',
+        1: '已审核',
+        9: '无需审核'
+      },
+
+      save_status_name_map: {
+        0: '待保存',
+        1: '已保存',
+        9: '无需保存'
+      },
+
       bound_status_list: [],
       product_list: [],
       product_map: [],
       columns: [
         { name: 'detail', label: '详情', field: 'detail', align: 'center' },
-        { name: 'billId', label: '表单序号', field: 'billId', align: 'center' },
+        // { name: 'billId', label: '表单序号', field: 'billId', align: 'center' },
         { name: 'number', label: '单据编号', field: 'number', align: 'center' },
         { name: 'type', label: '业务类型', field: 'type', align: 'center' },
         {
@@ -622,7 +707,7 @@ export default {
           field: 'audit_status',
           align: 'center'
         },
-                {
+        {
           name: 'save_status',
           label: '保存状态',
           field: 'save_status',
@@ -640,18 +725,18 @@ export default {
       ],
       // 列定义
       columns_batch: [
-        {
-          name: 'id',
-          label: '主单ID',
-          field: (row) => row.bound_billId,
-          align: 'center'
-        },
-        {
-          name: 'entryid',
-          label: '详单ID',
-          field: (row) => row.entryIds,
-          align: 'center'
-        },
+        // {
+        //   name: "id",
+        //   label: "主单ID",
+        //   field: (row) => row.bound_billId,
+        //   align: "center",
+        // },
+        // {
+        //   name: "entryid",
+        //   label: "详单ID",
+        //   field: (row) => row.entryIds,
+        //   align: "center",
+        // },
         {
           name: 'production_batch',
           label: 'ERP批次号',
@@ -758,6 +843,118 @@ export default {
   },
   methods: {
     // 检查阶段处理
+    // 获取过滤选项
+    getFilterOptions (columnName) {
+      switch (columnName) {
+        case 'type':
+          return [
+            { label: '生产入库', value: 1 },
+            { label: '采购入库', value: 2 },
+            { label: '其他入库', value: 3 },
+            { label: '调拨入库', value: 4 }
+          ]
+        case 'audit_status':
+          return [
+            { label: '待审核', value: 0 },
+            { label: '已审核', value: 1 },
+            { label: '无需审核', value: 9 }
+          ]
+        case 'save_status':
+          return [
+            { label: '待保存', value: 0 },
+            { label: '已保存', value: 1 },
+            { label: '无需保存', value: 9 }
+          ]
+        case 'bound_status':
+          return [
+            { label: '待审核', value: 0 },
+            { label: '确认无误', value: 1 }
+          ]
+        case 'department':
+          return this.bound_department_list
+        default:
+          return []
+      }
+    },
+    // 处理过滤变化
+    handleFilterChange () {
+      this.pagination.page = 1
+      this.getSearchList(1)
+    },
+
+    handleHeaderDblClick (column) {
+      // 排除不需要搜索的列
+      if (['detail', 'action'].includes(column.name)) return
+
+      this.activeSearchField = column.field
+      this.activeSearchLabel = column.label
+
+      // 弹出搜索对话框
+      this.$q
+        .dialog({
+          title: `搜索${column.label}`,
+          message: `请输入${column.label}的搜索条件`,
+          prompt: {
+            model: '',
+            type: 'text'
+          },
+          cancel: true,
+          persistent: true
+        })
+        .onOk((data) => {
+          // 执行搜索
+          this.executeColumnSearch(column.field, data)
+        })
+        .onCancel(() => {
+          this.activeSearchField = ''
+          this.activeSearchLabel = ''
+        })
+    },
+
+    // 执行列搜索
+    executeColumnSearch (field, value) {
+      // 构建搜索参数
+      if (
+        field === 'type' ||
+        field === 'audit_status' ||
+        field === 'save_status' ||
+        field === 'bound_status'
+      ) {
+        const searchParams = {
+          [field]: value
+        }
+        // 清除其他搜索条件
+        this.filter = ''
+        this.date_range = ''
+
+        // 执行搜索
+        this.getList({
+          ...searchParams,
+          page: 1
+        })
+
+        // 重置激活的搜索字段
+        this.activeSearchField = ''
+        this.activeSearchLabel = ''
+      } else {
+        const searchParams = {
+          [field + '__icontains']: value
+        }
+        // 清除其他搜索条件
+        this.filter = ''
+        this.date_range = ''
+
+        // 执行搜索
+        this.getList({
+          ...searchParams,
+          page: 1
+        })
+
+        // 重置激活的搜索字段
+        this.activeSearchField = ''
+        this.activeSearchLabel = ''
+      }
+    },
     checkStage (stage) {
       const _this = this
 
@@ -1037,6 +1234,7 @@ export default {
           return '未知'
       }
     },
+
     getList (params = {}) {
       var _this = this
       _this.loading = true
@@ -1089,13 +1287,24 @@ export default {
       }
       this.getSearchList(this.current)
     },
-    // 带搜索条件加载
+
+    // 修改搜索方法以包含过滤条件
     getSearchList (page = 1) {
       this.current = page
       this.paginationIpt = page
+
+      // 构建过滤参数
+      const filterParams = {}
+      for (const [key, value] of Object.entries(this.filterModels)) {
+        if (value !== null && value !== '') {
+          filterParams[key] = value
+        }
+      }
+
       this.getList({
         number__icontains: this.filter,
-        document_date__range: this.date_range
+        document_date__range: this.date_range,
+        ...filterParams // 添加过滤条件
       })
     },
     getfileList () {
@@ -1225,6 +1434,46 @@ export default {
           _this.getSearchList()
         })
     },
+    delete_data (e) {
+      var _this = this
+
+      // 设置要删除的数据ID(根据你的数据结构调整)
+      _this.deleteid = e.billId // 如果e是行数据对象,可能需要使用e.id或e.billId
+      _this.choose_bill_code = e.number // 保存单据编号用于显示
+
+      // 创建确认对话框
+      _this.$q
+        .dialog({
+          title: '确认删除',
+          message: `确定要删除单据编号为【${_this.choose_bill_code}】的记录吗?此操作不可撤销。`,
+          cancel: true,
+          persistent: true,
+          ok: {
+            push: true,
+            label: '删除',
+            color: 'negative'
+          },
+          cancel: {
+            push: true,
+            label: '取消',
+            color: 'primary'
+          }
+        })
+        .onOk(() => {
+          // 用户确认删除
+          _this.deleteDataSubmit()
+        })
+        .onCancel(() => {
+          // 用户取消删除
+          _this.deleteid = 0
+          _this.choose_bill_code = ''
+          _this.$q.notify({
+            message: '已取消删除操作',
+            icon: 'info',
+            color: 'info'
+          })
+        })
+    },
 
     detailData (e) {
       var _this = this
@@ -1263,7 +1512,6 @@ export default {
       var _this = this
       deleteauth(_this.pathname + _this.deleteid + '/')
         .then((res) => {
-          _this.deleteDataCancel()
           _this.getSearchList()
           _this.$q.notify({
             message: '成功删除数据',
@@ -1360,7 +1608,7 @@ export default {
         })
       })
 
-    getauth('warehouse/department/', {})
+    getauth('warehouse/department/?max_page=1000', {})
       .then((res) => {
         _this.bound_department_list = res.results.map((item) => ({
           label: item.department_name,

+ 290 - 18
templates/src/pages/erp/erpdn.vue

@@ -16,6 +16,43 @@
         flat
         bordered
       >
+        <template v-slot:header-cell="props">
+          <q-th :props="props" @dblclick="handleHeaderDblClick(props.col)">
+            <!-- 为特定列添加下拉选择器 -->
+            <template
+              v-if="
+                [
+                  'type',
+                  'audit_status',
+                  'save_status',
+                  'bound_status',
+                  'department',
+                ].includes(props.col.name)
+              "
+            >
+              <q-select
+                dense
+                outlined
+                v-model="filterModels[props.col.name]"
+                :options="getFilterOptions(props.col.name)"
+                option-label="label"
+                option-value="value"
+                emit-value
+                map-options
+                clearable
+                @input="handleFilterChange"
+                style="min-width: 120px"
+              >
+                <template v-slot:prepend>
+                  <span class="text-caption">{{ props.col.label }}</span>
+                </template>
+              </q-select>
+            </template>
+            <template v-else>
+              {{ props.col.label }}
+            </template>
+          </q-th>
+        </template>
         <template v-slot:top>
           <q-btn-group push>
             <q-btn :label="$t('refresh')" icon="refresh" @click="reFresh()">
@@ -155,6 +192,31 @@
               >
             </template>
 
+            <template v-if="props.row.id === editid">
+              <q-td key="audit_status" :props="props">{{
+                audit_status_name_map[props.row.audit_status] ||
+                props.row.audit_status
+              }}</q-td>
+            </template>
+            <template v-else-if="props.row.id !== editid">
+              <q-td key="audit_status" :props="props">{{
+                audit_status_name_map[props.row.audit_status] ||
+                props.row.audit_status
+              }}</q-td>
+            </template>
+            <template v-if="props.row.id === editid">
+              <q-td key="save_status" :props="props">{{
+                save_status_name_map[props.row.save_status] ||
+                props.row.save_status
+              }}</q-td>
+            </template>
+            <template v-else-if="props.row.id !== editid">
+              <q-td key="save_status" :props="props">{{
+                save_status_name_map[props.row.save_status] ||
+                props.row.save_status
+              }}</q-td>
+            </template>
+
             <template v-if="props.row.id === editid">
               <q-td key="date" :props="props">{{ props.row.date }}</q-td>
             </template>
@@ -212,6 +274,20 @@
                     >单据无误</q-tooltip
                   >
                 </q-btn>
+                <q-btn
+                  round
+                  flat
+                  push
+                  color="deep-purple"
+                  icon="delete"
+                  @click="delete_data(props.row)"
+                >
+                  <q-tooltip
+                    content-class="bg-amber text-black shadow-4"
+                    :offset="[10, 10]"
+                    >{{ $t("delete") }}</q-tooltip
+                  >
+                </q-btn>
               </q-td>
             </template>
             <template v-else-if="editMode">
@@ -555,6 +631,16 @@ export default {
   name: 'Pageasnlist',
   data () {
     return {
+      // 新增:过滤模型
+      filterModels: {
+        type: null,
+        audit_status: null,
+        save_status: null,
+        bound_status: null,
+        department: null
+      },
+      activeSearchField: '', // 当前激活的搜索字段
+      activeSearchLabel: '', // 当前激活的搜索字段的标签
       createDate2: '',
       date_range: '',
       proxyDate: '',
@@ -589,12 +675,24 @@ export default {
       bound_desc_map: [],
       bound_department_list: [],
       bound_department_map: [],
+      audit_status_name_map: {
+        0: '待审核',
+        1: '已审核',
+        9: '无需审核'
+      },
+
+      save_status_name_map: {
+        0: '待保存',
+        1: '已保存',
+        9: '无需保存'
+      },
+
       bound_status_list: [],
       product_list: [],
       product_map: [],
       columns: [
         { name: 'detail', label: '详情', field: 'detail', align: 'center' },
-        { name: 'billId', label: '表单序号', field: 'billId', align: 'center' },
+        // { name: 'billId', label: '表单序号', field: 'billId', align: 'center' },
         { name: 'number', label: '单据编号', field: 'number', align: 'center' },
         { name: 'type', label: '业务类型', field: 'type', align: 'center' },
         {
@@ -603,6 +701,18 @@ export default {
           field: 'department',
           align: 'center'
         },
+        {
+          name: 'audit_status',
+          label: '审核状态',
+          field: 'audit_status',
+          align: 'center'
+        },
+        {
+          name: 'save_status',
+          label: '保存状态',
+          field: 'save_status',
+          align: 'center'
+        },
         { name: 'date', label: '单据日期', field: 'date', align: 'center' },
         { name: 'creater', label: '经办人', field: 'creater', align: 'center' },
         {
@@ -615,18 +725,18 @@ export default {
       ],
       // 列定义
       columns_batch: [
-        {
-          name: 'id',
-          label: '主单ID',
-          field: (row) => row.bound_billId,
-          align: 'center'
-        },
-        {
-          name: 'entryid',
-          label: '详单ID',
-          field: (row) => row.entryIds,
-          align: 'center'
-        },
+        // {
+        //   name: "id",
+        //   label: "主单ID",
+        //   field: (row) => row.bound_billId,
+        //   align: "center",
+        // },
+        // {
+        //   name: "entryid",
+        //   label: "详单ID",
+        //   field: (row) => row.entryIds,
+        //   align: "center",
+        // },
         {
           name: 'production_batch',
           label: 'ERP批次号',
@@ -733,6 +843,117 @@ export default {
   },
   methods: {
     // 检查阶段处理
+    // 获取过滤选项
+    getFilterOptions (columnName) {
+      switch (columnName) {
+        case 'type':
+          return [
+            { label: '销售出库', value: 1 },
+            { label: '生产领料', value: 2 },
+            { label: '其他出库', value: 3 }
+          ]
+        case 'audit_status':
+          return [
+            { label: '待审核', value: 0 },
+            { label: '已审核', value: 1 },
+            { label: '无需审核', value: 9 }
+          ]
+        case 'save_status':
+          return [
+            { label: '待保存', value: 0 },
+            { label: '已保存', value: 1 },
+            { label: '无需保存', value: 9 }
+          ]
+        case 'bound_status':
+          return [
+            { label: '待审核', value: 0 },
+            { label: '确认无误', value: 1 }
+          ]
+        case 'department':
+          return this.bound_department_list
+        default:
+          return []
+      }
+    },
+    // 处理过滤变化
+    handleFilterChange () {
+      this.pagination.page = 1
+      this.getSearchList(1)
+    },
+
+    handleHeaderDblClick (column) {
+      // 排除不需要搜索的列
+      if (['detail', 'action'].includes(column.name)) return
+
+      this.activeSearchField = column.field
+      this.activeSearchLabel = column.label
+
+      // 弹出搜索对话框
+      this.$q
+        .dialog({
+          title: `搜索${column.label}`,
+          message: `请输入${column.label}的搜索条件`,
+          prompt: {
+            model: '',
+            type: 'text'
+          },
+          cancel: true,
+          persistent: true
+        })
+        .onOk((data) => {
+          // 执行搜索
+          this.executeColumnSearch(column.field, data)
+        })
+        .onCancel(() => {
+          this.activeSearchField = ''
+          this.activeSearchLabel = ''
+        })
+    },
+
+    // 执行列搜索
+    executeColumnSearch (field, value) {
+      // 构建搜索参数
+      if (
+        field === 'type' ||
+        field === 'audit_status' ||
+        field === 'save_status' ||
+        field === 'bound_status'
+      ) {
+        const searchParams = {
+          [field]: value
+        }
+        // 清除其他搜索条件
+        this.filter = ''
+        this.date_range = ''
+
+        // 执行搜索
+        this.getList({
+          ...searchParams,
+          page: 1
+        })
+
+        // 重置激活的搜索字段
+        this.activeSearchField = ''
+        this.activeSearchLabel = ''
+      } else {
+        const searchParams = {
+          [field + '__icontains']: value
+        }
+        // 清除其他搜索条件
+        this.filter = ''
+        this.date_range = ''
+
+        // 执行搜索
+        this.getList({
+          ...searchParams,
+          page: 1
+        })
+
+        // 重置激活的搜索字段
+        this.activeSearchField = ''
+        this.activeSearchLabel = ''
+      }
+    },
     checkStage (stage) {
       const _this = this
 
@@ -1009,13 +1230,14 @@ export default {
           return '未知'
       }
     },
+
     getList (params = {}) {
       var _this = this
       _this.loading = true
       // 合并基础参数
       const baseParams = {
         page: _this.current,
-        base_type: '0',
+        base_type: '1',
         page_size: _this.pagination.rowsPerPage
       }
       // 创建URLSearchParams处理参数
@@ -1061,13 +1283,24 @@ export default {
       }
       this.getSearchList(this.current)
     },
-    // 带搜索条件加载
+
+    // 修改搜索方法以包含过滤条件
     getSearchList (page = 1) {
       this.current = page
       this.paginationIpt = page
+
+      // 构建过滤参数
+      const filterParams = {}
+      for (const [key, value] of Object.entries(this.filterModels)) {
+        if (value !== null && value !== '') {
+          filterParams[key] = value
+        }
+      }
+
       this.getList({
         number__icontains: this.filter,
-        document_date__range: this.date_range
+        document_date__range: this.date_range,
+        ...filterParams // 添加过滤条件
       })
     },
     getfileList () {
@@ -1197,6 +1430,46 @@ export default {
           _this.getSearchList()
         })
     },
+    delete_data (e) {
+      var _this = this
+
+      // 设置要删除的数据ID(根据你的数据结构调整)
+      _this.deleteid = e.billId // 如果e是行数据对象,可能需要使用e.id或e.billId
+      _this.choose_bill_code = e.number // 保存单据编号用于显示
+
+      // 创建确认对话框
+      _this.$q
+        .dialog({
+          title: '确认删除',
+          message: `确定要删除单据编号为【${_this.choose_bill_code}】的记录吗?此操作不可撤销。`,
+          cancel: true,
+          persistent: true,
+          ok: {
+            push: true,
+            label: '删除',
+            color: 'negative'
+          },
+          cancel: {
+            push: true,
+            label: '取消',
+            color: 'primary'
+          }
+        })
+        .onOk(() => {
+          // 用户确认删除
+          _this.deleteDataSubmit()
+        })
+        .onCancel(() => {
+          // 用户取消删除
+          _this.deleteid = 0
+          _this.choose_bill_code = ''
+          _this.$q.notify({
+            message: '已取消删除操作',
+            icon: 'info',
+            color: 'info'
+          })
+        })
+    },
 
     detailData (e) {
       var _this = this
@@ -1235,7 +1508,6 @@ export default {
       var _this = this
       deleteauth(_this.pathname + _this.deleteid + '/')
         .then((res) => {
-          _this.deleteDataCancel()
           _this.getSearchList()
           _this.$q.notify({
             message: '成功删除数据',
@@ -1332,7 +1604,7 @@ export default {
         })
       })
 
-    getauth('warehouse/department/', {})
+    getauth('warehouse/department/?max_page=1000', {})
       .then((res) => {
         _this.bound_department_list = res.results.map((item) => ({
           label: item.department_name,