diff --git a/inventory-backend/app/services/bom_service.py b/inventory-backend/app/services/bom_service.py index 616c218..0839027 100644 --- a/inventory-backend/app/services/bom_service.py +++ b/inventory-backend/app/services/bom_service.py @@ -3,6 +3,7 @@ from app.models.bom import BomTable from app.models.base import MaterialBase from app.models.inbound.buy import StockBuy from sqlalchemy import func, distinct, or_, case +from collections import defaultdict import uuid from datetime import datetime @@ -64,6 +65,7 @@ class BomService: BomTable.parent_id, MaterialBase.name.label('parent_name'), MaterialBase.spec_model.label('parent_spec'), + MaterialBase.category.label('parent_category'), BomTable.is_enabled, func.count(BomTable.child_id).label('child_count') ).join( @@ -72,7 +74,7 @@ class BomService: BomTable.bom_no == bom_no, BomTable.version == version ).group_by( - BomTable.parent_id, MaterialBase.name, MaterialBase.spec_model, BomTable.is_enabled + BomTable.parent_id, MaterialBase.name, MaterialBase.spec_model, MaterialBase.category, BomTable.is_enabled ).first() if summary: @@ -82,12 +84,39 @@ class BomService: 'parent_id': summary.parent_id, 'parent_name': summary.parent_name, 'parent_spec': summary.parent_spec or '', + 'parent_category': summary.parent_category or '', 'is_enabled': summary.is_enabled, 'child_count': summary.child_count }) results.sort(key=lambda x: (x['bom_no'], x['version']), reverse=True) - return results + + # 如果有关键词,过滤结果(keyword 匹配逻辑保持不变) + if keyword: + kw = f'%{keyword}%' + results = [ + r for r in results + if kw in (r.get('parent_name') or '') + or kw in (r.get('parent_spec') or '') + or kw in (r.get('bom_no') or '') + or kw in (r.get('parent_category') or '') + ] + + # 按 parent_category 分组 + grouped = defaultdict(list) + for item in results: + cat = item.get('parent_category') or '未分类' + grouped[cat].append(item) + + grouped_list = [] + for cat, items in sorted(grouped.items(), key=lambda x: x[0]): + grouped_list.append({ + 'category': cat, + 'count': len(items), + 'items': items + }) + + return grouped_list @staticmethod def get_bom_detail(bom_no, version=None): diff --git a/inventory-web/src/views/bom/BomManage.vue b/inventory-web/src/views/bom/BomManage.vue index c7c2f3e..ebaf54b 100644 --- a/inventory-web/src/views/bom/BomManage.vue +++ b/inventory-web/src/views/bom/BomManage.vue @@ -8,7 +8,7 @@ + 全部展开 + 全部折叠 新建 BOM - - - - - - - - - - - - - - - +
+ + + + + + + + + + + + + + + + + + + + + +
@@ -268,7 +283,8 @@ let originalVersion = '' let currentBomNo = '' let originalChildren: ChildRow[] = [] -const bomList = ref([]) +const bomGroups = ref([]) // 分组结构: [{category, count, items[]}] +const activeCategories = ref([]) // 默认全部展开 const searchKeyword = ref('') const childSearchKeyword = ref('') @@ -560,8 +576,9 @@ const pureBomNo = computed(() => form.bom_no) const versionOptions = computed(() => { const ver = originalVersion || 'V1.0' + const allItems = bomGroups.value.flatMap((g: any) => g.items) const occupiedVersions = new Set( - bomList.value.filter(item => item.bom_no === currentBomNo).map(item => item.version) + allItems.filter((item: any) => item.bom_no === currentBomNo).map((item: any) => item.version) ) const getNextMinor = (baseMajor: number, baseMinor: number): string => { let minor = baseMinor + 1 @@ -597,7 +614,10 @@ const fetchBomList = async () => { loading.value = true try { const res = await getBomList({ keyword: searchKeyword.value }) - if (res.code === 200) bomList.value = res.data + if (res.code === 200) { + bomGroups.value = res.data + activeCategories.value = res.data.map((g: any) => g.category) + } } finally { loading.value = false } }