diff --git a/inventory-backend/app/api/v1/inbound/product.py b/inventory-backend/app/api/v1/inbound/product.py index c276606..9ec367b 100644 --- a/inventory-backend/app/api/v1/inbound/product.py +++ b/inventory-backend/app/api/v1/inbound/product.py @@ -78,7 +78,40 @@ def get_list(): category = request.args.get('category', '') material_type = request.args.get('material_type', '') company = request.args.get('company', '') - result = ProductInboundService.get_list(page, limit, keyword, statuses, category, material_type, company) + order_by_column = request.args.get('orderByColumn', '') + is_asc = request.args.get('isAsc', '') + advanced_filters_str = request.args.get('advancedFilters', '') + + # 准备额外筛选字典 + extra_filters = {} + if company: + extra_filters['company'] = company + if category: + extra_filters['category'] = category + if material_type: + extra_filters['material_type'] = material_type + if order_by_column: + extra_filters['order_by_column'] = order_by_column + if is_asc: + extra_filters['is_asc'] = is_asc + if advanced_filters_str: + try: + import json + advanced_filters = json.loads(advanced_filters_str) + extra_filters['advanced_filters'] = advanced_filters + except Exception: + extra_filters['advanced_filters'] = [] + + # 调用服务,传入所有参数 + result = ProductInboundService.get_list( + page, limit, keyword, statuses, + category=extra_filters.get('category'), + material_type=extra_filters.get('material_type'), + company=extra_filters.get('company'), + order_by_column=extra_filters.get('order_by_column'), + is_asc=extra_filters.get('is_asc'), + advanced_filters=extra_filters.get('advanced_filters') + ) user_permissions = get_current_user_permissions() if result.get('items'): result['items'] = [filter_item_by_permissions(item, user_permissions) for item in result['items']] @@ -184,4 +217,4 @@ def calculate_bom_cost(): return jsonify({"code": 200, "msg": "success", "data": cost}) except Exception as e: traceback.print_exc() - return jsonify({"code": 500, "msg": str(e)}), 500 \ No newline at end of file + return jsonify({"code": 500, "msg": str(e)}), 500 diff --git a/inventory-backend/app/services/inbound/product_service.py b/inventory-backend/app/services/inbound/product_service.py index 7e02dca..d3bb806 100644 --- a/inventory-backend/app/services/inbound/product_service.py +++ b/inventory-backend/app/services/inbound/product_service.py @@ -270,7 +270,8 @@ class ProductInboundService: return [] @staticmethod - def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None, company=None): + def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None, company=None, + order_by_column=None, is_asc=None, advanced_filters=None): from app.models.inbound.product import StockProduct try: query = db.session.query(StockProduct).outerjoin(MaterialBase, StockProduct.base_id == MaterialBase.id) @@ -304,8 +305,118 @@ class ProductInboundService: StockProduct.stock_quantity > 0 ) ) - pagination = query.order_by(StockProduct.production_date.desc()).paginate(page=page, per_page=limit, - error_out=False) + + # 高级动态筛选 + if advanced_filters: + if isinstance(advanced_filters, str): + try: + import json + advanced_filters = json.loads(advanced_filters) + except: + advanced_filters = [] + if isinstance(advanced_filters, list): + field_mapping = { + 'id': StockProduct.id, + 'base_id': StockProduct.base_id, + 'company_name': MaterialBase.company_name, + 'material_name': MaterialBase.name, + 'spec_model': MaterialBase.spec_model, + 'category': MaterialBase.category, + 'material_type': MaterialBase.material_type, + 'unit': MaterialBase.unit, + 'sku': StockProduct.sku, + 'inbound_date': StockProduct.production_date, + 'barcode': StockProduct.barcode, + 'serial_number': StockProduct.serial_number, + 'batch_number': StockProduct.serial_number, + 'status': StockProduct.status, + 'quality_status': StockProduct.quality_status, + 'in_quantity': StockProduct.in_quantity, + 'stock_quantity': StockProduct.stock_quantity, + 'available_quantity': StockProduct.available_quantity, + 'warehouse_location': StockProduct.warehouse_location, + 'bom_code': StockProduct.bom_code, + 'bom_version': StockProduct.bom_version, + 'work_order_code': StockProduct.work_order_code, + 'raw_material_cost': StockProduct.raw_material_cost, + 'unit_total_cost': StockProduct.manual_cost, + 'order_id': StockProduct.order_id, + 'sale_price': StockProduct.sale_price, + 'production_manager': StockProduct.production_manager, + } + for cond in advanced_filters: + field = cond.get('field') + operator = cond.get('operator') + value = cond.get('value') + if not field or not operator: + continue + model_field = field_mapping.get(field) + if model_field is None: + continue + # 防止 SQL 注入,只允许映射的字段 + if operator == '=': + query = query.filter(model_field == value) + elif operator == '!=': + query = query.filter(model_field != value) + elif operator == 'like': + query = query.filter(model_field.ilike(f'%{value}%')) + elif operator == 'not_like': + query = query.filter(~model_field.ilike(f'%{value}%')) + elif operator == '>': + if value.replace('.', '', 1).isdigit(): + query = query.filter(model_field > float(value)) + elif operator == '<': + if value.replace('.', '', 1).isdigit(): + query = query.filter(model_field < float(value)) + elif operator == '>=': + if value.replace('.', '', 1).isdigit(): + query = query.filter(model_field >= float(value)) + elif operator == '<=': + if value.replace('.', '', 1).isdigit(): + query = query.filter(model_field <= float(value)) + + # 动态排序 + order_field = None + if order_by_column and is_asc is not None: + order_mapping = { + 'id': StockProduct.id, + 'base_id': StockProduct.base_id, + 'company_name': MaterialBase.company_name, + 'material_name': MaterialBase.name, + 'category': MaterialBase.category, + 'material_type': MaterialBase.material_type, + 'spec_model': MaterialBase.spec_model, + 'unit': MaterialBase.unit, + 'sku': StockProduct.sku, + 'inbound_date': StockProduct.production_date, + 'barcode': StockProduct.barcode, + 'serial_number': StockProduct.serial_number, + 'batch_number': StockProduct.serial_number, + 'status': StockProduct.status, + 'quality_status': StockProduct.quality_status, + 'in_quantity': StockProduct.in_quantity, + 'stock_quantity': StockProduct.stock_quantity, + 'available_quantity': StockProduct.available_quantity, + 'warehouse_location': StockProduct.warehouse_location, + 'bom_code': StockProduct.bom_code, + 'bom_version': StockProduct.bom_version, + 'work_order_code': StockProduct.work_order_code, + 'raw_material_cost': StockProduct.raw_material_cost, + 'unit_total_cost': StockProduct.manual_cost, + 'order_id': StockProduct.order_id, + 'sale_price': StockProduct.sale_price, + 'production_manager': StockProduct.production_manager, + } + order_field = order_mapping.get(order_by_column) + if order_field is not None: + if is_asc == 'true' or is_asc == True: + query = query.order_by(order_field.asc()) + else: + query = query.order_by(order_field.desc()) + if order_field is None: + query = query.order_by(StockProduct.production_date.desc()) + + pagination = query.paginate(page=page, per_page=limit, error_out=False) current_items = pagination.items def parse_img(json_str): @@ -321,7 +432,7 @@ class ProductInboundService: item_dict['unit_total_cost'] = float(item.manual_cost or 0) items.append(item_dict) return {"total": pagination.total, "items": items} - except: + except Exception as e: traceback.print_exc() return {"total": 0, "items": []} diff --git a/inventory-web/src/views/stock/inbound/product.vue b/inventory-web/src/views/stock/inbound/product.vue index 4c4759e..aa3b4c0 100644 --- a/inventory-web/src/views/stock/inbound/product.vue +++ b/inventory-web/src/views/stock/inbound/product.vue @@ -53,6 +53,36 @@ 搜索 重置 + + +
+
+ + + + + + + + 删除 +
+
+ 添加条件 +
+ 重置 + 应用 +
+
+
+
+