diff --git a/inventory-backend/app/api/v1/inbound/semi.py b/inventory-backend/app/api/v1/inbound/semi.py index d76f82a..ebd88a5 100644 --- a/inventory-backend/app/api/v1/inbound/semi.py +++ b/inventory-backend/app/api/v1/inbound/semi.py @@ -8,7 +8,7 @@ inbound_semi_bp = Blueprint('inbound_semi', __name__) # ------------------------------------------------------------------ -# 0. 基础物料搜索 (复用逻辑) +# 0. 基础物料搜索 # ------------------------------------------------------------------ @inbound_semi_bp.route('/search-base', methods=['GET']) def search_base(): @@ -18,7 +18,6 @@ def search_base(): """ try: keyword = request.args.get('keyword', '') - # 这里复用 Service 中的搜索逻辑 data = SemiInboundService.search_base_material(keyword) return jsonify({ "code": 200, @@ -38,10 +37,13 @@ def get_list(): try: page = request.args.get('page', 1, type=int) limit = request.args.get('pageSize', 15, type=int) - # 支持按关键字搜索:BOM号、工单号、SN、批号等 keyword = request.args.get('keyword', '') - result = SemiInboundService.get_list(page, limit, keyword) + # 获取状态列表参数 + statuses_str = request.args.get('statuses', '') + statuses = statuses_str.split(',') if statuses_str else [] + + result = SemiInboundService.get_list(page, limit, keyword, statuses) return jsonify({"code": 200, "msg": "success", "data": result}) except Exception as e: traceback.print_exc() @@ -49,7 +51,7 @@ def get_list(): # ------------------------------------------------------------------ -# 2. 新增半成品入库 (修改:返回创建的对象数据) +# 2. 新增半成品入库 # ------------------------------------------------------------------ @inbound_semi_bp.route('/submit', methods=['POST']) def submit(): @@ -58,10 +60,8 @@ def submit(): if not data: return jsonify({"code": 400, "msg": "No data"}), 400 - # 修改:调用 Service 处理入库,获取新创建的对象 new_stock = SemiInboundService.handle_inbound(data) - # 修改:返回成功信息以及新创建的数据(包含生成的ID和SKU),供前端打印使用 return jsonify({ "code": 200, "msg": "入库成功", diff --git a/inventory-backend/app/services/inbound/semi_service.py b/inventory-backend/app/services/inbound/semi_service.py index 27f5c62..43e1fd4 100644 --- a/inventory-backend/app/services/inbound/semi_service.py +++ b/inventory-backend/app/services/inbound/semi_service.py @@ -2,7 +2,7 @@ from app.extensions import db from app.models.base import MaterialBase from datetime import datetime -from sqlalchemy import or_, func, text +from sqlalchemy import or_, func, text, and_ # Added and_ import traceback import json @@ -130,7 +130,7 @@ class SemiInboundService: batch_number=data.get('batch_number'), barcode=final_barcode, - status='在库', + status=data.get('status', '在库'), # 默认在库 quality_status=data.get('quality_status', '合格'), in_quantity=in_qty, stock_quantity=in_qty, @@ -150,7 +150,6 @@ class SemiInboundService: manual_cost=manual_cost, total_price=total_value, - # [核心修改] 将列表转为 JSON 字符串存储 arrival_photo=json.dumps(arrival_list), quality_report_link=json.dumps(quality_report_list), @@ -199,7 +198,6 @@ class SemiInboundService: if frontend_key in data: setattr(stock, db_attr, data[frontend_key]) - # [核心修改] 图片字段更新 (List -> JSON String) if 'arrival_photo' in data: imgs = data['arrival_photo'] if isinstance(imgs, list): @@ -244,9 +242,8 @@ class SemiInboundService: if 'in_quantity' in data: new_qty = float(data['in_quantity']) - old_qty = float(stock.in_quantity) - if new_qty != old_qty: - diff = new_qty - old_qty + diff = new_qty - float(stock.in_quantity) + if diff != 0: stock.in_quantity = new_qty stock.stock_quantity = float(stock.stock_quantity) + diff stock.available_quantity = float(stock.available_quantity) + diff @@ -288,49 +285,71 @@ class SemiInboundService: raise e @staticmethod - def get_list(page, limit, keyword=None): + def get_list(page, limit, keyword=None, statuses=None): from app.models.inbound.semi import StockSemi try: query = db.session.query(StockSemi).outerjoin(MaterialBase, StockSemi.base_id == MaterialBase.id) + # 1. 关键词搜索 if keyword: + kw = f'%{keyword}%' query = query.filter( or_( - MaterialBase.name.ilike(f'%{keyword}%'), - MaterialBase.spec_model.ilike(f'%{keyword}%'), - StockSemi.batch_number.ilike(f'%{keyword}%'), - StockSemi.serial_number.ilike(f'%{keyword}%'), - StockSemi.sku.ilike(f'%{keyword}%'), - StockSemi.work_order_code.ilike(f'%{keyword}%'), - StockSemi.bom_code.ilike(f'%{keyword}%') + MaterialBase.name.ilike(kw), + MaterialBase.spec_model.ilike(kw), + StockSemi.batch_number.ilike(kw), + StockSemi.serial_number.ilike(kw), + StockSemi.sku.ilike(kw), + StockSemi.work_order_code.ilike(kw), + StockSemi.bom_code.ilike(kw) + ) + ) + + # 2. 状态筛选与零库存隐藏逻辑 + if not statuses: + statuses = ['在库', '借库'] + + # 如果筛选包含'已出库',则显示所有数量;否则隐藏 stock_quantity <= 0 的记录 + if '已出库' in statuses: + query = query.filter(StockSemi.status.in_(statuses)) + else: + query = query.filter( + and_( + StockSemi.status.in_(statuses), + StockSemi.stock_quantity > 0 ) ) pagination = query.order_by(StockSemi.id.desc()).paginate(page=page, per_page=limit, error_out=False) - current_items = pagination.items - base_ids = list(set([item.base_id for item in current_items if item.base_id])) - stock_map = {} - if base_ids: - aggregates = db.session.query( - StockSemi.base_id, - func.sum(StockSemi.stock_quantity).label('total_stock'), - func.sum(StockSemi.available_quantity).label('total_avail') - ).filter(StockSemi.base_id.in_(base_ids)).group_by(StockSemi.base_id).all() - - for agg in aggregates: - stock_map[agg.base_id] = { - 'total_stock': float(agg.total_stock or 0), - 'total_avail': float(agg.total_avail or 0) - } + # 3. 数据组装 (移除 aggregation map,使用单行数据) + def parse_img(json_str): + if not json_str: return [] + try: + return json.loads(json_str) if json_str.startswith('[') else [json_str] + except: + return [] items = [] for item in current_items: - stats = stock_map.get(item.base_id, {'total_stock': 0, 'total_avail': 0}) d = item.to_dict() - d['sum_stock'] = stats['total_stock'] - d['sum_available'] = stats['total_avail'] + + # 直接使用当前行的库存,不再聚合 + 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) return {"total": pagination.total, "items": items} diff --git a/inventory-web/src/views/stock/inbound/semi.vue b/inventory-web/src/views/stock/inbound/semi.vue index 75171a3..f2e4861 100644 --- a/inventory-web/src/views/stock/inbound/semi.vue +++ b/inventory-web/src/views/stock/inbound/semi.vue @@ -9,11 +9,25 @@ clearable @clear="fetchData" @keyup.enter="fetchData" + style="width: 300px; margin-right: 10px;" > + + + + + +
@@ -66,21 +80,24 @@ -