feat: 首页全局搜索支持按 SKU 查库位——采购/半成品/成品库存纳入搜索并显示库位

This commit is contained in:
yueli
2026-09-07 15:47:25 +08:00
parent 803e8a1532
commit 220f73acbd
2 changed files with 43 additions and 24 deletions

View File

@ -3,6 +3,8 @@ from flask import jsonify, request
from . import common_bp from . import common_bp
from app.models import MaterialBase from app.models import MaterialBase
from app.models.inbound.buy import StockBuy from app.models.inbound.buy import StockBuy
from app.models.inbound.semi import StockSemi
from app.models.inbound.product import StockProduct
from app.models.bom import BomTable from app.models.bom import BomTable
from app.extensions import db from app.extensions import db
@ -46,31 +48,38 @@ def global_search():
"extra": {"category": b.category or ''} "extra": {"category": b.category or ''}
}) })
# ── 2. 采购库 (StockBuy) ───────────────────────────────── # ── 2. 库存三表(采购/半成品/成品):按 SKU/条码/名称命中,显示所在库位 ──
# 真实字段: barcode, sku (通过 join 搜索关联的 MaterialBase.name) def _append_stock_items(model, type_key, badge):
stock_conditions = [] conds = []
for kw in keywords: for kw in keywords:
kw_term = f'%{kw}%' t = f'%{kw}%'
stock_conditions.append( c = db.or_(
db.or_( MaterialBase.name.ilike(t),
MaterialBase.name.ilike(kw_term), model.sku.ilike(t),
StockBuy.barcode.ilike(kw_term), model.barcode.ilike(t),
StockBuy.sku.ilike(kw_term)
) )
) if hasattr(model, 'serial_number'):
stocks = StockBuy.query.join(MaterialBase, StockBuy.base_id == MaterialBase.id).filter( c = db.or_(c, model.serial_number.ilike(t))
db.and_(*stock_conditions) conds.append(c)
).all() rows = (model.query.join(MaterialBase, model.base_id == MaterialBase.id)
for s in stocks: .filter(db.and_(*conds)).order_by(model.id.desc()).limit(50).all())
merged_list.append({ for s in rows:
"id": s.base_id, merged_list.append({
"stock_id": s.id, "id": s.base_id,
"type": "stock_buy", "stock_id": s.id,
"title": s.base.name if s.base else '未知物料', "type": type_key,
"subtitle": f"条码: {s.barcode or '无'} | 库存: {s.stock_quantity}", "title": s.base.name if s.base else '未知物料',
"badge": "采购库", "subtitle": f"SKU: {s.sku or '-'} | 库位: {s.warehouse_location or '-'} | 库存: {s.stock_quantity or 0}",
"extra": {"barcode": s.barcode or '', "status": s.status or ''} "badge": badge,
}) "extra": {
"sku": s.sku or '', "warehouse_location": s.warehouse_location or '',
"stock_id": s.id, "source_table": model.__tablename__,
}
})
_append_stock_items(StockBuy, 'stock_buy', '采购库')
_append_stock_items(StockSemi, 'stock_semi', '半成品')
_append_stock_items(StockProduct, 'stock_product', '成品')
# ── 3. BOM 配方 (BomTable) ────────────────────────────── # ── 3. BOM 配方 (BomTable) ──────────────────────────────
# 真实字段: bom_no, version # 真实字段: bom_no, version

View File

@ -268,6 +268,8 @@ const getBadgeType = (type: string) => {
const map: Record<string, string> = { const map: Record<string, string> = {
'material': 'success', 'material': 'success',
'stock_buy': 'primary', 'stock_buy': 'primary',
'stock_semi': 'warning',
'stock_product': 'info',
'bom': 'warning' 'bom': 'warning'
} }
return map[type] || 'info' return map[type] || 'info'
@ -313,6 +315,14 @@ const handleSearchSelect = (item: any) => {
path: '/bom', path: '/bom',
query: { keyword: item.title } query: { keyword: item.title }
}) })
} else if (item.type === 'stock_semi' || item.type === 'stock_product' || item.type === 'stock_buy') {
// 库存命中:弹出该条记录的库位,便于快速定位(采购库仍保留跳库存页)
const loc = item.extra?.warehouse_location || '-'
if (item.type === 'stock_buy') {
router.push({ path: '/inventory/buy', query: { keyword: item.title } })
} else {
ElMessage.success(`【${item.title}】库位:${loc}`)
}
} }
} }