From b1cc280a711d377827644d61a614c8bd016c50dd Mon Sep 17 00:00:00 2001 From: dxc Date: Wed, 11 Mar 2026 13:37:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E6=A1=86=E4=B8=BA=E5=A4=8D=E5=90=88=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E9=80=89=E6=8B=A9=EF=BC=8C=E6=94=AF=E6=8C=81=E6=8C=89?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=E3=80=81=E4=BF=97=E5=90=8D=E3=80=81=E8=A7=84?= =?UTF-8?q?=E6=A0=BC=E8=BF=9B=E8=A1=8C=E7=B2=BE=E5=87=86=E6=9F=A5=E6=9D=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- inventory-backend/app/api/v1/inbound/base.py | 3 +- inventory-backend/app/api/v1/inbound/buy.py | 3 +- .../app/api/v1/inbound/product.py | 3 +- inventory-backend/app/api/v1/inbound/semi.py | 3 +- .../app/services/inbound/base_service.py | 25 +++++++---- .../app/services/inbound/buy_service.py | 41 +++++++++++++------ .../app/services/inbound/product_service.py | 33 ++++++++++----- .../app/services/inbound/semi_service.py | 37 +++++++++++------ inventory-web/src/views/material/list.vue | 20 +++++++-- inventory-web/src/views/stock/inbound/buy.vue | 17 ++++++-- .../src/views/stock/inbound/product.vue | 18 +++++--- .../src/views/stock/inbound/semi.vue | 18 +++++--- 12 files changed, 156 insertions(+), 65 deletions(-) diff --git a/inventory-backend/app/api/v1/inbound/base.py b/inventory-backend/app/api/v1/inbound/base.py index 50b0bae..2960999 100644 --- a/inventory-backend/app/api/v1/inbound/base.py +++ b/inventory-backend/app/api/v1/inbound/base.py @@ -124,7 +124,8 @@ def get_list(): 'isAsc': request.args.get('isAsc', None), 'advancedFilters': advanced_filters_list, 'enableWarningSort': request.args.get('enableWarningSort', 'false').lower() == 'true', - 'has_stock': request.args.get('has_stock', '') + 'has_stock': request.args.get('has_stock', ''), + 'searchField': request.args.get('searchField', 'all') } user_permissions = get_current_user_permissions() diff --git a/inventory-backend/app/api/v1/inbound/buy.py b/inventory-backend/app/api/v1/inbound/buy.py index db8e927..52c6adc 100644 --- a/inventory-backend/app/api/v1/inbound/buy.py +++ b/inventory-backend/app/api/v1/inbound/buy.py @@ -116,6 +116,7 @@ def get_list(): limit = request.args.get('pageSize', 15, type=int) keyword = request.args.get('keyword', '') sku = request.args.get('sku', '') + search_field = request.args.get('searchField', 'all') # 新增筛选参数 category = request.args.get('category', '') @@ -138,7 +139,7 @@ def get_list(): statuses_str = request.args.get('statuses', '') statuses = statuses_str.split(',') if statuses_str else [] - result = BuyInboundService.get_list(page, limit, keyword, sku, statuses, category, material_type, company, + result = BuyInboundService.get_list(page, limit, keyword, sku, search_field, statuses, category, material_type, company, order_by, is_asc, advanced_filters) # 字段级脱敏 user_permissions = get_current_user_permissions() diff --git a/inventory-backend/app/api/v1/inbound/product.py b/inventory-backend/app/api/v1/inbound/product.py index 13a0908..7202292 100644 --- a/inventory-backend/app/api/v1/inbound/product.py +++ b/inventory-backend/app/api/v1/inbound/product.py @@ -74,6 +74,7 @@ def get_list(): limit = request.args.get('pageSize', 15, type=int) keyword = request.args.get('keyword', '') sku = request.args.get('sku', '') + search_field = request.args.get('searchField', 'all') statuses_str = request.args.get('statuses', '') statuses = statuses_str.split(',') if statuses_str else [] category = request.args.get('category', '') @@ -105,7 +106,7 @@ def get_list(): # 调用服务,传入所有参数 result = ProductInboundService.get_list( - page, limit, keyword, sku, statuses, + page, limit, keyword, sku, search_field, statuses, category=extra_filters.get('category'), material_type=extra_filters.get('material_type'), company=extra_filters.get('company'), diff --git a/inventory-backend/app/api/v1/inbound/semi.py b/inventory-backend/app/api/v1/inbound/semi.py index 4ffc7bd..cfe97a4 100644 --- a/inventory-backend/app/api/v1/inbound/semi.py +++ b/inventory-backend/app/api/v1/inbound/semi.py @@ -74,6 +74,7 @@ def get_list(): limit = request.args.get('pageSize', 15, type=int) keyword = request.args.get('keyword', '') sku = request.args.get('sku', '') + search_field = request.args.get('searchField', 'all') statuses_str = request.args.get('statuses', '') statuses = statuses_str.split(',') if statuses_str else [] company = request.args.get('company', '') @@ -105,7 +106,7 @@ def get_list(): # 调用服务,传入所有参数 result = SemiInboundService.get_list( - page, limit, keyword, sku, statuses, + page, limit, keyword, sku, search_field, statuses, **extra_filters ) user_permissions = get_current_user_permissions() diff --git a/inventory-backend/app/services/inbound/base_service.py b/inventory-backend/app/services/inbound/base_service.py index 0c85933..c0af62e 100644 --- a/inventory-backend/app/services/inbound/base_service.py +++ b/inventory-backend/app/services/inbound/base_service.py @@ -169,14 +169,23 @@ class MaterialBaseService: .outerjoin(MaterialWarningSetting, MaterialBase.id == MaterialWarningSetting.base_id) if filters: - # 1. 关键词模糊搜索 - if filters.get('keyword'): - kw = f"%{filters['keyword']}%" - query = query.filter(or_( - MaterialBase.name.ilike(kw), - MaterialBase.common_name.ilike(kw), - MaterialBase.spec_model.ilike(kw) - )) + # 1. 关键词精准搜索(支持指定字段) + search_field = filters.get('searchField', 'all') + keyword = filters.get('keyword') + if keyword: + kw = f"%{keyword}%" + if search_field == 'name': + query = query.filter(MaterialBase.name.ilike(kw)) + elif search_field == 'common_name': + query = query.filter(MaterialBase.common_name.ilike(kw)) + elif search_field == 'spec': + query = query.filter(MaterialBase.spec_model.ilike(kw)) + else: # 'all' 默认全局模糊匹配 + query = query.filter(or_( + MaterialBase.name.ilike(kw), + MaterialBase.common_name.ilike(kw), + MaterialBase.spec_model.ilike(kw) + )) # 2. 精确筛选 company = filters.get('company') diff --git a/inventory-backend/app/services/inbound/buy_service.py b/inventory-backend/app/services/inbound/buy_service.py index e96ac72..365ed14 100644 --- a/inventory-backend/app/services/inbound/buy_service.py +++ b/inventory-backend/app/services/inbound/buy_service.py @@ -240,26 +240,41 @@ class BuyInboundService: # 5. 获取列表 (支持排序和高级筛选) # ============================================================ @staticmethod - def get_list(page, limit, keyword=None, sku=None, statuses=None, category=None, material_type=None, company=None, + def get_list(page, limit, keyword=None, sku=None, search_field='all', 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. 通用关键词搜索(名称、规格、公司) + # 1. 通用关键词搜索(支持指定字段精准搜索) if keyword: k_str = f'%{keyword.strip()}%' - conditions = [ - StockBuy.barcode.ilike(k_str), - StockBuy.batch_number.ilike(k_str), - StockBuy.serial_number.ilike(k_str), - StockBuy.supplier_name.ilike(k_str), - StockBuy.buyer_name.ilike(k_str), - MaterialBase.name.ilike(k_str), - MaterialBase.spec_model.ilike(k_str), - MaterialBase.company_name.ilike(k_str), # 关键词也支持搜公司 - ] - query = query.filter(or_(*conditions)) + if search_field == 'name': + query = query.filter(MaterialBase.name.ilike(k_str)) + elif search_field == 'spec': + query = query.filter(MaterialBase.spec_model.ilike(k_str)) + elif search_field == 'common_name': + query = query.filter(MaterialBase.common_name.ilike(k_str)) + elif search_field == 'barcode': + query = query.filter(StockBuy.barcode.ilike(k_str)) + elif search_field == 'batch_number': + query = query.filter(StockBuy.batch_number.ilike(k_str)) + elif search_field == 'supplier_name': + query = query.filter(StockBuy.supplier_name.ilike(k_str)) + elif search_field == 'buyer_name': + query = query.filter(StockBuy.buyer_name.ilike(k_str)) + else: # 'all' 默认全局模糊匹配 + conditions = [ + StockBuy.barcode.ilike(k_str), + StockBuy.batch_number.ilike(k_str), + StockBuy.serial_number.ilike(k_str), + StockBuy.supplier_name.ilike(k_str), + StockBuy.buyer_name.ilike(k_str), + MaterialBase.name.ilike(k_str), + MaterialBase.spec_model.ilike(k_str), + MaterialBase.company_name.ilike(k_str), + ] + query = query.filter(or_(*conditions)) # 1.1 SKU 独立搜索 if sku and sku.strip(): diff --git a/inventory-backend/app/services/inbound/product_service.py b/inventory-backend/app/services/inbound/product_service.py index d9cc528..5f4c447 100644 --- a/inventory-backend/app/services/inbound/product_service.py +++ b/inventory-backend/app/services/inbound/product_service.py @@ -270,22 +270,35 @@ class ProductInboundService: return [] @staticmethod - def get_list(page, limit, keyword=None, sku=None, statuses=None, category=None, material_type=None, company=None, + def get_list(page, limit, keyword=None, sku=None, search_field='all', 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) - # 1. 通用关键词搜索(名称、规格、公司) + # 1. 通用关键词搜索(支持指定字段精准搜索) if keyword: kw = f'%{keyword}%' - query = query.filter(or_( - MaterialBase.name.ilike(kw), - MaterialBase.spec_model.ilike(kw), - MaterialBase.company_name.ilike(kw), - StockProduct.serial_number.ilike(kw), - StockProduct.work_order_code.ilike(kw), - StockProduct.order_id.ilike(kw) - )) + if search_field == 'name': + query = query.filter(MaterialBase.name.ilike(kw)) + elif search_field == 'spec': + query = query.filter(MaterialBase.spec_model.ilike(kw)) + elif search_field == 'common_name': + query = query.filter(MaterialBase.common_name.ilike(kw)) + elif search_field == 'serial_number': + query = query.filter(StockProduct.serial_number.ilike(kw)) + elif search_field == 'work_order_code': + query = query.filter(StockProduct.work_order_code.ilike(kw)) + elif search_field == 'order_id': + query = query.filter(StockProduct.order_id.ilike(kw)) + else: # 'all' 默认全局模糊匹配 + query = query.filter(or_( + MaterialBase.name.ilike(kw), + MaterialBase.spec_model.ilike(kw), + MaterialBase.company_name.ilike(kw), + StockProduct.serial_number.ilike(kw), + StockProduct.work_order_code.ilike(kw), + StockProduct.order_id.ilike(kw) + )) # 1.1 SKU 独立搜索 if sku and sku.strip(): sku_str = f'%{sku.strip()}%' diff --git a/inventory-backend/app/services/inbound/semi_service.py b/inventory-backend/app/services/inbound/semi_service.py index aa41084..f7802ad 100644 --- a/inventory-backend/app/services/inbound/semi_service.py +++ b/inventory-backend/app/services/inbound/semi_service.py @@ -359,25 +359,38 @@ class SemiInboundService: return [] @staticmethod - def get_list(page, limit, keyword=None, sku=None, statuses=None, category=None, material_type=None, company=None, + def get_list(page, limit, keyword=None, sku=None, search_field='all', statuses=None, category=None, material_type=None, company=None, order_by_column=None, is_asc=None, advanced_filters=None): from app.models.inbound.semi import StockSemi try: query = db.session.query(StockSemi).outerjoin(MaterialBase, StockSemi.base_id == MaterialBase.id) - # 1. 通用关键词搜索(名称、规格、公司) + # 1. 通用关键词搜索(支持指定字段精准搜索) if keyword: kw = f'%{keyword}%' - query = query.filter( - or_( - MaterialBase.name.ilike(kw), - MaterialBase.spec_model.ilike(kw), - MaterialBase.company_name.ilike(kw), - StockSemi.batch_number.ilike(kw), - StockSemi.serial_number.ilike(kw), - StockSemi.work_order_code.ilike(kw), - StockSemi.bom_code.ilike(kw) + if search_field == 'name': + query = query.filter(MaterialBase.name.ilike(kw)) + elif search_field == 'spec': + query = query.filter(MaterialBase.spec_model.ilike(kw)) + elif search_field == 'common_name': + query = query.filter(MaterialBase.common_name.ilike(kw)) + elif search_field == 'batch_number': + query = query.filter(StockSemi.batch_number.ilike(kw)) + elif search_field == 'work_order_code': + query = query.filter(StockSemi.work_order_code.ilike(kw)) + elif search_field == 'bom_code': + query = query.filter(StockSemi.bom_code.ilike(kw)) + else: # 'all' 默认全局模糊匹配 + query = query.filter( + or_( + MaterialBase.name.ilike(kw), + MaterialBase.spec_model.ilike(kw), + MaterialBase.company_name.ilike(kw), + StockSemi.batch_number.ilike(kw), + StockSemi.serial_number.ilike(kw), + StockSemi.work_order_code.ilike(kw), + StockSemi.bom_code.ilike(kw) + ) ) - ) # 1.1 SKU 独立搜索 if sku and sku.strip(): sku_str = f'%{sku.strip()}%' diff --git a/inventory-web/src/views/material/list.vue b/inventory-web/src/views/material/list.vue index ab654c6..eec7ee0 100644 --- a/inventory-web/src/views/material/list.vue +++ b/inventory-web/src/views/material/list.vue @@ -5,11 +5,20 @@
+ @keyup.enter="handleQuery" + > + + ({ pageNum: 1, pageSize: 100, keyword: '', + searchField: 'all', category: '', type: '', company: '', @@ -966,6 +977,7 @@ const handleQuery = () => { const resetQuery = () => { queryParams.keyword = ''; + queryParams.searchField = 'all'; queryParams.category = ''; queryParams.type = ''; queryParams.company = ''; diff --git a/inventory-web/src/views/stock/inbound/buy.vue b/inventory-web/src/views/stock/inbound/buy.vue index 46dd5ac..74720d4 100644 --- a/inventory-web/src/views/stock/inbound/buy.vue +++ b/inventory-web/src/views/stock/inbound/buy.vue @@ -17,15 +17,22 @@ - + { const resetQuery = () => { queryParams.keyword = '' + queryParams.searchField = 'all' queryParams.sku = '' queryParams.category = '' queryParams.material_type = '' diff --git a/inventory-web/src/views/stock/inbound/product.vue b/inventory-web/src/views/stock/inbound/product.vue index de533a6..c3ba699 100644 --- a/inventory-web/src/views/stock/inbound/product.vue +++ b/inventory-web/src/views/stock/inbound/product.vue @@ -16,15 +16,22 @@ - + ('create') const tableData = ref([]) const total = ref(0) const formRef = ref() -const queryParams = reactive({ page: 1, pageSize: 50, keyword: '', sku: '', category: '', material_type: '', statuses: ['在库', '借库'], company: '', orderByColumn: '', isAsc: '', advancedFilters: [] }) +const queryParams = reactive({ page: 1, pageSize: 50, keyword: '', searchField: 'all', sku: '', category: '', material_type: '', statuses: ['在库', '借库'], company: '', orderByColumn: '', isAsc: '', advancedFilters: [] }) const categoryOptions = ref([]) const typeOptions = ref([]) const companyOptions = ref([]) // [新增] @@ -1018,6 +1025,7 @@ const loadWarehouseTree = async () => { const resetQuery = () => { queryParams.keyword = '' + queryParams.searchField = 'all' queryParams.sku = '' queryParams.category = '' queryParams.material_type = '' diff --git a/inventory-web/src/views/stock/inbound/semi.vue b/inventory-web/src/views/stock/inbound/semi.vue index c3313fc..5b3281c 100644 --- a/inventory-web/src/views/stock/inbound/semi.vue +++ b/inventory-web/src/views/stock/inbound/semi.vue @@ -17,15 +17,22 @@ - + ('create') const tableData = ref([]) const total = ref(0) const formRef = ref() -const queryParams = reactive({ page: 1, pageSize: 50, keyword: '', sku: '', category: '', material_type: '', statuses: ['在库', '借库'], company: '', orderByColumn: '', isAsc: '', advancedFilters: [] }) +const queryParams = reactive({ page: 1, pageSize: 50, keyword: '', searchField: 'all', sku: '', category: '', material_type: '', statuses: ['在库', '借库'], company: '', orderByColumn: '', isAsc: '', advancedFilters: [] }) const categoryOptions = ref([]) const typeOptions = ref([]) const companyOptions = ref([]) // [新增] @@ -1152,6 +1159,7 @@ const loadWarehouseTree = async () => { const resetQuery = () => { queryParams.keyword = '' + queryParams.searchField = 'all' queryParams.sku = '' queryParams.category = '' queryParams.material_type = ''