diff --git a/inventory-backend/app/api/v1/inbound/buy.py b/inventory-backend/app/api/v1/inbound/buy.py index ec8b85f..f6c0604 100644 --- a/inventory-backend/app/api/v1/inbound/buy.py +++ b/inventory-backend/app/api/v1/inbound/buy.py @@ -106,7 +106,7 @@ def search_base(): # ------------------------------------------------------------------ -# 1. 获取列表 (修改:接收 category 和 material_type) +# 1. 获取列表 (修改:接收 category, material_type, orderByColumn, isAsc, advancedFilters) # ------------------------------------------------------------------ @inbound_buy_bp.route('/list', methods=['GET']) @permission_required('inbound_buy') @@ -121,11 +121,24 @@ def get_list(): material_type = request.args.get('material_type', '') company = request.args.get('company', '') + # 排序参数 + order_by = request.args.get('orderByColumn', '').strip() + is_asc = request.args.get('isAsc', '').strip() + + # 高级筛选参数 + advanced_filters_raw = request.args.get('advancedFilters', '[]') + import json + try: + advanced_filters = json.loads(advanced_filters_raw) if advanced_filters_raw else [] + except json.JSONDecodeError: + advanced_filters = [] + # 状态参数处理 statuses_str = request.args.get('statuses', '') statuses = statuses_str.split(',') if statuses_str else [] - result = BuyInboundService.get_list(page, limit, keyword, statuses, category, material_type, company) + result = BuyInboundService.get_list(page, limit, keyword, statuses, category, material_type, company, + order_by, is_asc, advanced_filters) # 字段级脱敏 user_permissions = get_current_user_permissions() if result.get('items'): diff --git a/inventory-backend/app/services/inbound/buy_service.py b/inventory-backend/app/services/inbound/buy_service.py index 83bc411..77e3210 100644 --- a/inventory-backend/app/services/inbound/buy_service.py +++ b/inventory-backend/app/services/inbound/buy_service.py @@ -237,11 +237,13 @@ class BuyInboundService: raise e # ============================================================ - # 5. 获取列表 + # 5. 获取列表 (支持排序和高级筛选) # ============================================================ @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='', is_asc='', advanced_filters=None): try: + from sqlalchemy import and_, or_ query = db.session.query(StockBuy).outerjoin(MaterialBase, StockBuy.base_id == MaterialBase.id) # 1. 通用关键词搜索 @@ -279,7 +281,109 @@ class BuyInboundService: else: query = query.filter(and_(StockBuy.status.in_(statuses), StockBuy.stock_quantity > 0)) - pagination = query.order_by(StockBuy.in_date.desc()).paginate(page=page, per_page=limit, error_out=False) + # 5. 高级动态筛选 + if advanced_filters: + allowed_fields = { + 'company_name': MaterialBase.company_name, + 'material_name': MaterialBase.name, + 'material_type': MaterialBase.material_type, + 'category': MaterialBase.category, + 'spec_model': MaterialBase.spec_model, + 'unit': MaterialBase.unit, + 'sku': StockBuy.sku, + 'barcode': StockBuy.barcode, + 'batch_number': StockBuy.batch_number, + 'serial_number': StockBuy.serial_number, + 'warehouse_location': StockBuy.warehouse_location, + 'status': StockBuy.status, + 'inspection_status': StockBuy.inspection_status, + 'qty_inbound': StockBuy.in_quantity, + 'qty_stock': StockBuy.stock_quantity, + 'qty_available': StockBuy.available_quantity, + 'unit_price': StockBuy.pre_tax_unit_price, + 'total_price': StockBuy.total_price, + 'tax_rate': StockBuy.tax_rate, + 'currency': StockBuy.currency, + 'exchange_rate': StockBuy.exchange_rate, + 'supplier_name': StockBuy.supplier_name, + 'purchaser': StockBuy.buyer_name, + 'purchaser_email': StockBuy.buyer_email, + 'source_link': StockBuy.original_link, + 'detail_link': StockBuy.detail_link, + } + filter_conditions = [] + for condition in advanced_filters: + field = condition.get('field') + operator = condition.get('operator') + value = condition.get('value') + if not field or not operator or value is None: + continue + column = allowed_fields.get(field) + if column is None: + continue + if operator == 'eq': + filter_conditions.append(column == value) + elif operator == 'ne': + filter_conditions.append(column != value) + elif operator == 'contains': + filter_conditions.append(column.ilike(f'%{value}%')) + elif operator == 'ge': + try: + num_val = float(value) + filter_conditions.append(column >= num_val) + except ValueError: + continue + elif operator == 'le': + try: + num_val = float(value) + filter_conditions.append(column <= num_val) + except ValueError: + continue + if filter_conditions: + query = query.filter(and_(*filter_conditions)) + + # 6. 排序处理 + if order_by: + sort_field_map = { + 'company_name': MaterialBase.company_name, + 'material_name': MaterialBase.name, + 'material_type': MaterialBase.material_type, + 'category': MaterialBase.category, + 'spec_model': MaterialBase.spec_model, + 'unit': MaterialBase.unit, + 'sku': StockBuy.sku, + 'barcode': StockBuy.barcode, + 'inbound_date': StockBuy.in_date, + 'serial_number': StockBuy.serial_number, + 'batch_number': StockBuy.batch_number, + 'status': StockBuy.status, + 'inspection_status': StockBuy.inspection_status, + 'qty_inbound': StockBuy.in_quantity, + 'qty_stock': StockBuy.stock_quantity, + 'qty_available': StockBuy.available_quantity, + 'warehouse_loc': StockBuy.warehouse_location, + 'unit_price': StockBuy.pre_tax_unit_price, + 'total_price': StockBuy.total_price, + 'tax_rate': StockBuy.tax_rate, + 'currency': StockBuy.currency, + 'exchange_rate': StockBuy.exchange_rate, + 'supplier_name': StockBuy.supplier_name, + 'purchaser': StockBuy.buyer_name, + 'purchaser_email': StockBuy.buyer_email, + 'source_link': StockBuy.original_link, + 'detail_link': StockBuy.detail_link, + } + column = sort_field_map.get(order_by) + if column: + if is_asc == 'asc': + query = query.order_by(column.asc()) + elif is_asc == 'desc': + query = query.order_by(column.desc()) + else: + # 默认排序 + query = query.order_by(StockBuy.in_date.desc()) + + pagination = query.paginate(page=page, per_page=limit, error_out=False) items = [] for item in pagination.items: items.append(item.to_dict()) # 直接使用 model 的 to_dict diff --git a/inventory-web/src/views/stock/inbound/buy.vue b/inventory-web/src/views/stock/inbound/buy.vue index bc61c67..4866f13 100644 --- a/inventory-web/src/views/stock/inbound/buy.vue +++ b/inventory-web/src/views/stock/inbound/buy.vue @@ -53,6 +53,33 @@ 搜索 重置 + + +
+
+ + + + + + + + 删除 +
+
+ 添加条件 + 应用筛选 + 重置 +
+
+
@@ -90,6 +117,7 @@ class="modern-table" highlight-current-row header-cell-class-name="table-header-gray" + @sort-change="handleSortChange" >