From 31ddb1aafd9a25ec0ae203e333636ac8f3ea6f2c Mon Sep 17 00:00:00 2001 From: dxc Date: Tue, 24 Feb 2026 16:16:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E5=8D=8A=E6=88=90=E5=93=81=E6=88=90?= =?UTF-8?q?=E5=93=81=E5=90=8C=E6=A0=B7=E8=BF=9B=E8=A1=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=89=80=E5=B1=9E=E5=85=AC=E5=8F=B8=E4=BB=A5=E5=8F=8A=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/models/inbound/product.py | 10 +- inventory-backend/app/models/inbound/semi.py | 14 +- .../app/services/inbound/product_service.py | 74 +++--- .../app/services/inbound/semi_service.py | 60 +++-- inventory-web/src/views/stock/inbound/buy.vue | 5 - .../src/views/stock/inbound/product.vue | 210 +++++++++++++-- .../src/views/stock/inbound/semi.vue | 246 ++++++++++++++---- 7 files changed, 464 insertions(+), 155 deletions(-) diff --git a/inventory-backend/app/models/inbound/product.py b/inventory-backend/app/models/inbound/product.py index 7e55b03..d15cd24 100644 --- a/inventory-backend/app/models/inbound/product.py +++ b/inventory-backend/app/models/inbound/product.py @@ -3,6 +3,7 @@ from app.extensions import db import json from app.models.base import MaterialBase + class StockProduct(db.Model): """ 成品入库库存表 @@ -44,7 +45,7 @@ class StockProduct(db.Model): quality_report_link = db.Column(db.Text) # 质量报告 inspection_report_link = db.Column(db.Text) # 检测报告(旧字段升级为JSON) - # [新增] 成品实拍图 (JSON 存储) + # 成品实拍图 (JSON 存储) product_photo = db.Column(db.Text) detail_link = db.Column(db.Text) @@ -57,7 +58,7 @@ class StockProduct(db.Model): # 全局打印流水号 global_print_id = db.Column(db.Integer) - # 关系定义 [已修改] + # 关系定义 base = db.relationship('MaterialBase', back_populates='stock_products') def to_dict(self): @@ -79,7 +80,9 @@ class StockProduct(db.Model): return { 'id': self.id, 'base_id': self.base_id, - # [已修改] 使用 self.base + + # [新增] 公司名称 + 'company_name': self.base.company_name if self.base else '', 'material_name': self.base.name if self.base else '', 'spec_model': self.base.spec_model if self.base else '', 'category': self.base.category if self.base else '', @@ -115,7 +118,6 @@ class StockProduct(db.Model): 'quality_status': self.quality_status, - # [核心修改] 三个图片/链接字段全部解析为数组 'product_photo': parse_img_list(self.product_photo), 'quality_report_link': parse_img_list(self.quality_report_link), 'inspection_report_link': parse_img_list(self.inspection_report_link), diff --git a/inventory-backend/app/models/inbound/semi.py b/inventory-backend/app/models/inbound/semi.py index 7150e7b..92794a9 100644 --- a/inventory-backend/app/models/inbound/semi.py +++ b/inventory-backend/app/models/inbound/semi.py @@ -3,6 +3,7 @@ from app.extensions import db import json from app.models.base import MaterialBase + class StockSemi(db.Model): """ 半成品入库库存表 @@ -43,19 +44,19 @@ class StockSemi(db.Model): quality_status = db.Column(db.String(50)) - # [修改] 质量报告 (存储 JSON 字符串: 图片列表 + 链接) + # 质量报告 (存储 JSON 字符串: 图片列表 + 链接) quality_report_link = db.Column(db.Text) - # [新增] 到货图片 (存储 JSON 字符串) + # 到货图片 (存储 JSON 字符串) arrival_photo = db.Column(db.Text) detail_link = db.Column(db.Text) remark = db.Column(db.Text) - # [新增] 全局打印流水号 + # 全局打印流水号 global_print_id = db.Column(db.Integer) - # 关系定义 [已修改] + # 关系定义 base = db.relationship('MaterialBase', back_populates='stock_semis') def to_dict(self): @@ -78,7 +79,9 @@ class StockSemi(db.Model): return { 'id': self.id, 'base_id': self.base_id, - # [已修改] 使用 self.base + + # [新增] 公司名称 + 'company_name': self.base.company_name if self.base else '', 'material_name': self.base.name if self.base else '', 'spec_model': self.base.spec_model if self.base else '', 'category': self.base.category if self.base else '', @@ -115,7 +118,6 @@ class StockSemi(db.Model): 'quality_status': self.quality_status, - # [修改] 解析 JSON 字符串为数组返回给前端 'quality_report_link': parse_img_list(self.quality_report_link), 'arrival_photo': parse_img_list(self.arrival_photo), diff --git a/inventory-backend/app/services/inbound/product_service.py b/inventory-backend/app/services/inbound/product_service.py index 219f7d0..0163eed 100644 --- a/inventory-backend/app/services/inbound/product_service.py +++ b/inventory-backend/app/services/inbound/product_service.py @@ -33,10 +33,12 @@ class ProductInboundService: try: query = MaterialBase.query.filter(MaterialBase.is_enabled == True) if keyword: + kw = f'%{keyword}%' query = query.filter( or_( - MaterialBase.name.ilike(f'%{keyword}%'), - MaterialBase.spec_model.ilike(f'%{keyword}%') + MaterialBase.name.ilike(kw), + MaterialBase.spec_model.ilike(kw), + MaterialBase.company_name.ilike(kw) # [新增] ) ) query = query.order_by(MaterialBase.id.desc()).limit(20) @@ -44,6 +46,7 @@ class ProductInboundService: for item in query.all(): results.append({ 'id': item.id, + 'company_name': item.company_name, # [新增] 'name': item.name, 'spec': item.spec_model, 'category': item.category, @@ -57,13 +60,12 @@ class ProductInboundService: return [] # ============================================================ - # 1.5 [新增] BOM 搜索逻辑 + # 1.5 BOM 搜索逻辑 # ============================================================ @staticmethod def search_bom_options(keyword): from app.models.bom import BomTable try: - # 关联查询:BOM表 + 父件基础信息表 query = db.session.query( BomTable.bom_no, BomTable.version, @@ -71,13 +73,11 @@ class ProductInboundService: MaterialBase.spec_model.label('parent_spec') ).join(MaterialBase, BomTable.parent_id == MaterialBase.id) - # 只查询启用的BOM if hasattr(BomTable, 'is_enabled'): query = query.filter(BomTable.is_enabled == True) if keyword: kw = f'%{keyword}%' - # 支持搜索:BOM编号、父件名称、父件规格 query = query.filter( or_( BomTable.bom_no.ilike(kw), @@ -86,7 +86,6 @@ class ProductInboundService: ) ) - # 去重并限制数量 results = query.distinct().limit(20).all() return [{ @@ -283,23 +282,30 @@ class ProductInboundService: # 6. 获取列表 # ============================================================ @staticmethod - def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None): + def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None, company=None): from app.models.inbound.product import StockProduct try: query = db.session.query(StockProduct).outerjoin(MaterialBase, StockProduct.base_id == MaterialBase.id) if keyword: + kw = f'%{keyword}%' query = query.filter(or_( - MaterialBase.name.ilike(f'%{keyword}%'), - MaterialBase.spec_model.ilike(f'%{keyword}%'), - StockProduct.serial_number.ilike(f'%{keyword}%'), - StockProduct.work_order_code.ilike(f'%{keyword}%'), - StockProduct.order_id.ilike(f'%{keyword}%'), - StockProduct.sku.ilike(f'%{keyword}%') + 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), + StockProduct.sku.ilike(kw) )) if category and category.strip(): query = query.filter(MaterialBase.category == category.strip()) if material_type and material_type.strip(): query = query.filter(MaterialBase.material_type == material_type.strip()) + + # [新增] + if company and company.strip(): + query = query.filter(MaterialBase.company_name == company.strip()) + if not statuses: statuses = ['在库', '借库'] if '已出库' in statuses: @@ -324,23 +330,7 @@ class ProductInboundService: items = [] for item in current_items: - d = item.to_dict() - date_display = '' - if item.production_date: - try: - date_display = item.production_date.strftime('%Y-%m-%d') - except: - date_display = str(item.production_date)[:10] - d['inbound_date'] = date_display - d['qty_stock'] = float(item.stock_quantity or 0) - d['qty_available'] = float(item.available_quantity or 0) - d['sum_stock'] = d['qty_stock'] - d['sum_available'] = d['qty_available'] - d['product_photo'] = parse_img(item.product_photo) - d['quality_report_link'] = parse_img(item.quality_report_link) - d['inspection_report_link'] = parse_img(item.inspection_report_link) - d['global_print_id'] = item.global_print_id - items.append(d) + items.append(item.to_dict()) # 使用 Model to_dict return {"total": pagination.total, "items": items} except: traceback.print_exc() @@ -368,21 +358,37 @@ class ProductInboundService: except Exception: return [] + # ============================================================ + # 7. 获取筛选项 + # ============================================================ @staticmethod def get_filter_options(): try: from app.models.base import MaterialBase + # 类别 categories = db.session.query(MaterialBase.category) \ .filter(MaterialBase.category != None, MaterialBase.category != '') \ .distinct().all() + sorted_categories = sorted([r[0] for r in categories]) + + # 类型 types = db.session.query(MaterialBase.material_type) \ .filter(MaterialBase.material_type != None, MaterialBase.material_type != '') \ .distinct().all() + sorted_types = sorted([r[0] for r in types]) + + # [新增] 公司 + companies = db.session.query(MaterialBase.company_name) \ + .filter(MaterialBase.company_name != None, MaterialBase.company_name != '') \ + .distinct().all() + sorted_companies = sorted([r[0] for r in companies]) + return { - "categories": [r[0] for r in categories], - "types": [r[0] for r in types] + "categories": sorted_categories, + "types": sorted_types, + "companies": sorted_companies } except Exception: import traceback traceback.print_exc() - return {"categories": [], "types": []} \ No newline at end of file + return {"categories": [], "types": [], "companies": []} \ No newline at end of file diff --git a/inventory-backend/app/services/inbound/semi_service.py b/inventory-backend/app/services/inbound/semi_service.py index 89403a6..a032cbe 100644 --- a/inventory-backend/app/services/inbound/semi_service.py +++ b/inventory-backend/app/services/inbound/semi_service.py @@ -43,10 +43,12 @@ class SemiInboundService: try: query = MaterialBase.query.filter(MaterialBase.is_enabled == True) if keyword: + kw = f'%{keyword}%' query = query.filter( or_( - MaterialBase.name.ilike(f'%{keyword}%'), - MaterialBase.spec_model.ilike(f'%{keyword}%') + MaterialBase.name.ilike(kw), + MaterialBase.spec_model.ilike(kw), + MaterialBase.company_name.ilike(kw) # [新增] 支持搜公司 ) ) query = query.order_by(MaterialBase.id.desc()).limit(20) @@ -54,6 +56,7 @@ class SemiInboundService: for item in query.all(): results.append({ 'id': item.id, + 'company_name': item.company_name, # [新增] 'name': item.name, 'spec': item.spec_model, 'category': item.category, @@ -67,13 +70,12 @@ class SemiInboundService: return [] # ============================================================ - # 1.5 [新增] BOM 搜索逻辑 + # 1.5 BOM 搜索逻辑 # ============================================================ @staticmethod def search_bom_options(keyword): from app.models.bom import BomTable try: - # 关联查询:BOM表 + 父件基础信息表 query = db.session.query( BomTable.bom_no, BomTable.version, @@ -81,13 +83,11 @@ class SemiInboundService: MaterialBase.spec_model.label('parent_spec') ).join(MaterialBase, BomTable.parent_id == MaterialBase.id) - # 只查询启用的BOM if hasattr(BomTable, 'is_enabled'): query = query.filter(BomTable.is_enabled == True) if keyword: kw = f'%{keyword}%' - # 支持搜索:BOM编号、父件名称、父件规格 query = query.filter( or_( BomTable.bom_no.ilike(kw), @@ -96,7 +96,6 @@ class SemiInboundService: ) ) - # 去重并限制数量 results = query.distinct().limit(20).all() return [{ @@ -367,7 +366,7 @@ class SemiInboundService: # 6. 获取列表 # ============================================================ @staticmethod - def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None): + def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None, company=None): from app.models.inbound.semi import StockSemi try: query = db.session.query(StockSemi).outerjoin(MaterialBase, StockSemi.base_id == MaterialBase.id) @@ -377,6 +376,7 @@ class SemiInboundService: 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.sku.ilike(kw), @@ -388,6 +388,11 @@ class SemiInboundService: query = query.filter(MaterialBase.category == category.strip()) if material_type and material_type.strip(): query = query.filter(MaterialBase.material_type == material_type.strip()) + + # [新增] 公司筛选 + if company and company.strip(): + query = query.filter(MaterialBase.company_name == company.strip()) + if not statuses: statuses = ['在库', '借库'] if '已出库' in statuses: @@ -412,22 +417,7 @@ class SemiInboundService: items = [] for item in current_items: - d = item.to_dict() - date_display = '' - if item.production_date: - try: - date_display = item.production_date.strftime('%Y-%m-%d') - except: - date_display = str(item.production_date)[:10] - d['inbound_date'] = date_display - d['qty_stock'] = float(item.stock_quantity or 0) - d['qty_available'] = float(item.available_quantity or 0) - d['sum_stock'] = d['qty_stock'] - d['sum_available'] = d['qty_available'] - d['arrival_photo'] = parse_img(item.arrival_photo) - d['quality_report_link'] = parse_img(item.quality_report_link) - d['global_print_id'] = item.global_print_id - items.append(d) + items.append(item.to_dict()) # 直接使用 Model 的 to_dict (已包含 company_name) return {"total": pagination.total, "items": items} except Exception as e: print(f"List Error: {e}") @@ -456,21 +446,37 @@ class SemiInboundService: except Exception: return [] + # ============================================================ + # 7. 获取筛选项 (排序) + # ============================================================ @staticmethod def get_filter_options(): try: from app.models.base import MaterialBase + # 类别 categories = db.session.query(MaterialBase.category) \ .filter(MaterialBase.category != None, MaterialBase.category != '') \ .distinct().all() + sorted_categories = sorted([r[0] for r in categories]) + + # 类型 types = db.session.query(MaterialBase.material_type) \ .filter(MaterialBase.material_type != None, MaterialBase.material_type != '') \ .distinct().all() + sorted_types = sorted([r[0] for r in types]) + + # [新增] 公司 + companies = db.session.query(MaterialBase.company_name) \ + .filter(MaterialBase.company_name != None, MaterialBase.company_name != '') \ + .distinct().all() + sorted_companies = sorted([r[0] for r in companies]) + return { - "categories": [r[0] for r in categories], - "types": [r[0] for r in types] + "categories": sorted_categories, + "types": sorted_types, + "companies": sorted_companies } except Exception: import traceback traceback.print_exc() - return {"categories": [], "types": []} \ No newline at end of file + return {"categories": [], "types": [], "companies": []} \ No newline at end of file diff --git a/inventory-web/src/views/stock/inbound/buy.vue b/inventory-web/src/views/stock/inbound/buy.vue index 3bd3822..ed3a735 100644 --- a/inventory-web/src/views/stock/inbound/buy.vue +++ b/inventory-web/src/views/stock/inbound/buy.vue @@ -105,11 +105,6 @@ - - + +