Compare commits
3 Commits
67bc5b6c5d
...
9e83c31f39
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e83c31f39 | |||
| 6ad00884ba | |||
| 9a5e3ee6b0 |
@ -7,6 +7,7 @@ from app.models.inbound.semi import StockSemi
|
||||
from app.models.inbound.product import StockProduct
|
||||
from app.models.base import MaterialBase
|
||||
from sqlalchemy import desc, func, nullslast, asc, or_, and_
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
|
||||
class TransService:
|
||||
@ -396,8 +397,75 @@ class TransService:
|
||||
q = q.order_by(nullslast(asc(TransBorrow.expected_return_time)))
|
||||
pagination = q.paginate(page=page, per_page=limit, error_out=False)
|
||||
|
||||
# ============================================================
|
||||
# ★ 批量预加载物料名称(两步:收集ID → 批量 JOIN → 内存拼装)
|
||||
# ============================================================
|
||||
items_with_names = []
|
||||
items = pagination.items
|
||||
if items:
|
||||
# 步骤 1:收集所有 (source_table, stock_id) 对
|
||||
stock_ids_by_table = {'stock_buy': set(), 'stock_semi': set(), 'stock_product': set()}
|
||||
for item in items:
|
||||
if item.source_table in stock_ids_by_table and item.stock_id:
|
||||
stock_ids_by_table[item.source_table].add(item.stock_id)
|
||||
|
||||
# 步骤 2:批量查询库存表并 JOIN MaterialBase
|
||||
stock_map = {} # { ('stock_buy', 101): '物料名称', ... }
|
||||
model_map = {
|
||||
'stock_buy': StockBuy,
|
||||
'stock_semi': StockSemi,
|
||||
'stock_product': StockProduct
|
||||
}
|
||||
for table_name, ids in stock_ids_by_table.items():
|
||||
if not ids:
|
||||
continue
|
||||
ModelClass = model_map.get(table_name)
|
||||
if not ModelClass:
|
||||
continue
|
||||
stocks = ModelClass.query.options(
|
||||
joinedload(ModelClass.base)
|
||||
).filter(ModelClass.id.in_(ids)).all()
|
||||
for stock in stocks:
|
||||
name = stock.base.name if stock.base else ''
|
||||
stock_map[(table_name, stock.id)] = name
|
||||
|
||||
# 步骤 3(前置):收集 SKU 兜底候选集
|
||||
empty_sku_set = set()
|
||||
for item in items:
|
||||
name = stock_map.get((item.source_table, item.stock_id), '')
|
||||
if not name and item.sku:
|
||||
empty_sku_set.add(item.sku)
|
||||
|
||||
# 步骤 3(前置):SKU 兜底批量查询
|
||||
# 场景:库存记录被跨表转移(删旧建新)时,trans_borrow.stock_id 指向孤立记录
|
||||
# 通过 sku 在三张库存表中查找任意匹配,再通过 base_id 获取 MaterialBase.name
|
||||
sku_name_map = {}
|
||||
if empty_sku_set:
|
||||
for ModelClass in [StockProduct, StockSemi, StockBuy]:
|
||||
stocks = ModelClass.query.options(
|
||||
joinedload(ModelClass.base)
|
||||
).filter(
|
||||
ModelClass.sku.in_(empty_sku_set)
|
||||
).all()
|
||||
for stock in stocks:
|
||||
if stock.sku not in sku_name_map and stock.base:
|
||||
sku_name_map[stock.sku] = stock.base.name
|
||||
|
||||
# 步骤 3:为每条记录注入 material_name(含 SKU 兜底)
|
||||
for item in items:
|
||||
item_dict = item.to_dict()
|
||||
material_name = stock_map.get((item.source_table, item.stock_id), '')
|
||||
if not material_name and item.sku:
|
||||
material_name = sku_name_map.get(item.sku, '')
|
||||
item_dict['material_name'] = material_name
|
||||
items_with_names.append(item_dict)
|
||||
|
||||
items_data = items_with_names
|
||||
else:
|
||||
items_data = []
|
||||
|
||||
return {
|
||||
'items': [r.to_dict() for r in pagination.items],
|
||||
'items': items_data,
|
||||
'total': pagination.total,
|
||||
'page': page,
|
||||
'limit': limit
|
||||
|
||||
@ -239,7 +239,7 @@ const handleLogout = () => {
|
||||
<footer v-if="!isLoginPage" class="app-footer">
|
||||
<span class="version-tag">
|
||||
<el-icon style="vertical-align: middle; margin-right: 4px"><InfoFilled /></el-icon>
|
||||
当前版本:V3.45
|
||||
当前版本:V3.46
|
||||
</span>
|
||||
</footer>
|
||||
|
||||
|
||||
@ -35,27 +35,50 @@
|
||||
stripe
|
||||
style="margin-top:20px"
|
||||
v-loading="loading"
|
||||
type="expand"
|
||||
>
|
||||
<el-table-column type="expand">
|
||||
<template #default="props">
|
||||
<div style="padding: 10px 40px;">
|
||||
<h4 style="margin: 0 0 10px; font-size: 14px; color: #606266;">借出明细</h4>
|
||||
<el-table :data="props.row.children" border size="small">
|
||||
<el-table-column prop="material_name" label="物料名称" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="sku" label="SKU" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="借出数量" width="80" align="center">
|
||||
<template #default="{row}">
|
||||
<el-tag type="info">{{ row.quantity }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已还数量" width="80" align="center">
|
||||
<template #default="{row}">
|
||||
<el-tag type="success">{{ row.returned_quantity || 0 }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="待还数量" width="80" align="center">
|
||||
<template #default="{row}">
|
||||
<el-tag v-if="row.pending_quantity > 0" type="warning">{{ row.pending_quantity }}</el-tag>
|
||||
<el-tag v-else type="success">0</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="return_location" label="归还库位" min-width="120">
|
||||
<template #default="{row}">
|
||||
<span v-if="row.return_location">{{ row.return_location }}</span>
|
||||
<span v-else style="color:#ccc">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="hasColumnPermission('borrow_no')" prop="borrow_no" label="单号" width="180" show-overflow-tooltip />
|
||||
<el-table-column v-if="hasColumnPermission('borrower_name')" prop="borrower_name" label="借用人" width="100" />
|
||||
<el-table-column v-if="hasColumnPermission('sku')" prop="sku" label="SKU" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="借出数量" width="90" align="center">
|
||||
<template #default="{row}">
|
||||
<el-tag type="info">{{ row.quantity }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已还数量" width="90" align="center">
|
||||
<template #default="{row}">
|
||||
<el-tag type="success">{{ row.returned_quantity || 0 }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="待还数量" width="90" align="center">
|
||||
<template #default="{row}">
|
||||
<el-tag v-if="row.pending_quantity > 0" type="warning">{{ row.pending_quantity }}</el-tag>
|
||||
<el-tag v-else type="success">0</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="hasColumnPermission('borrow_time')" prop="borrow_time" label="借出时间" width="160" sortable />
|
||||
<el-table-column label="借出物品" width="90" align="center">
|
||||
<template #default="{row}">
|
||||
<el-tag type="info">{{ row.children ? row.children.length : 0 }} 项</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="hasColumnPermission('return_operator')" prop="return_operator" label="归还人" width="100" />
|
||||
|
||||
<el-table-column v-if="hasColumnPermission('expected_return_time') || hasColumnPermission('return_time')" label="归还时间 / 预计" min-width="200">
|
||||
@ -88,13 +111,6 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="hasColumnPermission('return_location')" label="归还库位" min-width="120">
|
||||
<template #default="{row}">
|
||||
<span v-if="row.return_location">{{ row.return_location }}</span>
|
||||
<span v-else style="color:#ccc">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="hasColumnPermission('borrow_signature') || hasColumnPermission('return_signature')" label="电子签名" width="140" align="center">
|
||||
<template #default="{row}">
|
||||
<div style="display:flex; justify-content: center; gap:10px">
|
||||
@ -205,7 +221,20 @@ const fetchData = async () => {
|
||||
search_type: searchType.value
|
||||
}
|
||||
})
|
||||
list.value = res.data.items
|
||||
|
||||
// ★ 按 borrow_no 分组聚合为主子表结构
|
||||
const groupMap = new Map()
|
||||
;(res.data.items || []).forEach(item => {
|
||||
if (!groupMap.has(item.borrow_no)) {
|
||||
groupMap.set(item.borrow_no, {
|
||||
...item,
|
||||
children: []
|
||||
})
|
||||
}
|
||||
groupMap.get(item.borrow_no).children.push(item)
|
||||
})
|
||||
list.value = Array.from(groupMap.values())
|
||||
|
||||
total.value = res.data.total
|
||||
} finally { loading.value = false }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user