From 1edd471208842e8c9dd14dc4d820cdf026edd87b Mon Sep 17 00:00:00 2001 From: DXC Date: Tue, 12 May 2026 15:27:47 +0800 Subject: [PATCH] =?UTF-8?q?feat(bom):=20BOM=E5=88=97=E8=A1=A8=E6=8C=89?= =?UTF-8?q?=E7=89=A9=E6=96=99=E7=B1=BB=E5=88=AB=E5=88=86=E7=BB=84=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=EF=BC=8C=E6=94=AF=E6=8C=81=E6=8A=98=E5=8F=A0=E5=B1=95?= =?UTF-8?q?=E5=BC=80=E4=B8=8E=E6=95=B0=E9=87=8F=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- inventory-backend/app/services/bom_service.py | 33 +++++++- inventory-web/src/views/bom/BomManage.vue | 78 ++++++++++++------- 2 files changed, 80 insertions(+), 31 deletions(-) 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 } }