feat: add advanced filtering and full-field sorting to material list

Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
This commit is contained in:
dxc
2026-03-02 15:22:04 +08:00
parent 9b794d7f64
commit c5872aed3c
2 changed files with 83 additions and 13 deletions

View File

@ -5,6 +5,7 @@ from app.services.inbound.base_service import MaterialBaseService
from app.utils.decorators import login_required, permission_required
import traceback
import datetime
import json
inbound_base_bp = Blueprint('stock_base', __name__)
@ -105,6 +106,13 @@ def get_list():
page = request.args.get('pageNum', 1, type=int)
limit = request.args.get('pageSize', 10, type=int)
# 解析高级筛选条件
advanced_filters_raw = request.args.get('advancedFilters', '[]')
try:
advanced_filters_list = json.loads(advanced_filters_raw)
except:
advanced_filters_list = []
# 构造筛选条件
filters = {
'keyword': request.args.get('keyword', ''),
@ -113,7 +121,8 @@ def get_list():
'type': request.args.get('type', ''),
'isEnabled': request.args.get('isEnabled', None),
'orderByColumn': request.args.get('orderByColumn', ''),
'isAsc': request.args.get('isAsc', None)
'isAsc': request.args.get('isAsc', None),
'advancedFilters': advanced_filters_list
}
result = MaterialBaseService.get_list(page, limit, filters)

View File

@ -112,7 +112,7 @@ class MaterialBaseService:
@staticmethod
def get_list(page, limit, filters=None):
"""
获取基础信息列表 (带分页和筛选)
获取基础信息列表 (带分页、高级筛选和全字段排序)
"""
try:
# 构建聚合子查询
@ -178,19 +178,80 @@ class MaterialBaseService:
is_active = bool(int(filters['isEnabled']))
query = query.filter_by(is_enabled=is_active)
# 排序处理
# 3. 高级动态筛选
advanced_filters = filters.get('advancedFilters', [])
if advanced_filters:
allowed_fields = {
'companyName': 'company_name',
'name': 'name',
'commonName': 'common_name',
'category': 'category',
'type': 'material_type',
'spec': 'spec_model',
'unit': 'unit',
'inventoryCount': total_inv,
'availableCount': total_avail
}
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
db_field = allowed_fields.get(field)
if not db_field:
continue
# 对于聚合字段 (inventoryCount, availableCount),需要使用子查询别名
if isinstance(db_field, type(total_inv)):
column = db_field
else:
column = getattr(MaterialBase, db_field, None)
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))
# 排序处理(支持全字段)
order_by_column = filters.get('orderByColumn', '')
is_asc = filters.get('isAsc', None)
if order_by_column == 'inventoryCount':
if order_by_column:
# 字段映射
sort_field_map = {
'companyName': MaterialBase.company_name,
'name': MaterialBase.name,
'commonName': MaterialBase.common_name,
'category': MaterialBase.category,
'type': MaterialBase.material_type,
'spec': MaterialBase.spec_model,
'unit': MaterialBase.unit,
'inventoryCount': total_inv,
'availableCount': total_avail
}
sort_column = sort_field_map.get(order_by_column)
if sort_column is not None:
if is_asc == 'asc':
query = query.order_by(total_inv.asc())
else:
query = query.order_by(total_inv.desc())
elif order_by_column == 'availableCount':
if is_asc == 'asc':
query = query.order_by(total_avail.asc())
else:
query = query.order_by(total_avail.desc())
query = query.order_by(sort_column.asc())
elif is_asc == 'desc':
query = query.order_by(sort_column.desc())
else:
# 默认排序:优先按总库存数降序,当库存相同时,再按规格型号升序
query = query.order_by(total_inv.desc(), MaterialBase.spec_model.asc())