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;"
>