diff --git a/backend/my_work/routers/apiWarehouse.go b/backend/my_work/routers/apiWarehouse.go index 43b2dca..0e1c236 100644 --- a/backend/my_work/routers/apiWarehouse.go +++ b/backend/my_work/routers/apiWarehouse.go @@ -115,6 +115,47 @@ func canModifyWarehouse(userID, creatorUserID uint) bool { return userID == creatorUserID } +// buildContainerBreadcrumb 根据容器 ID 和映射表构建面包屑路径(如 "仓库A / 柜子B / 抽屉C") +func buildContainerBreadcrumb(containerID uint, containerMap map[uint]TabWarehouseContainer) string { + parts := []string{} + visited := map[uint]bool{} + cur := containerID + for cur != 0 && !visited[cur] { + visited[cur] = true + c, ok := containerMap[cur] + if !ok { + // 映射表中没有,查询数据库补全 + var missing TabWarehouseContainer + if models.DB.Where("id = ?", cur).First(&missing).Error == nil { + containerMap[cur] = missing + parts = append([]string{missing.Title}, parts...) + if missing.ParentID == nil { + break + } + cur = *missing.ParentID + continue + } + break + } + parts = append([]string{c.Title}, parts...) + if c.ParentID == nil { + break + } + cur = *c.ParentID + } + if len(parts) == 0 { + return "" + } + result := "" + for i, p := range parts { + if i > 0 { + result += " / " + } + result += p + } + return result +} + // ---------- 初始化 ---------- func ApiWarehouseInit() { @@ -382,7 +423,10 @@ func ApiWarehouse(r *gin.RouterGroup) { ReturnJson(ctx, "jsonErr", nil) return } - if from.Entries <= 0 || from.Entries > 300 { + if from.AllLevels && from.Entries <= 0 { + from.Entries = 5000 + } + if from.Entries <= 0 || (!from.AllLevels && from.Entries > 300) { from.Entries = 10 } if from.Page <= 0 { @@ -813,13 +857,45 @@ func ApiWarehouse(r *gin.RouterGroup) { Find(&items) canModifyItems := make([]bool, len(items)) + // 收集所有涉及的容器 ID + containerIDs := make(map[uint]bool) for i, item := range items { canModifyItems[i] = canModifyWarehouse(user.ID, item.CreatorID) + if item.ContainerID != nil { + containerIDs[*item.ContainerID] = true + } + } + + // 批量查询容器,构建 ID→Container 映射 + containerMap := make(map[uint]TabWarehouseContainer) + if len(containerIDs) > 0 { + ids := make([]uint, 0, len(containerIDs)) + for id := range containerIDs { + ids = append(ids, id) + } + var containers []TabWarehouseContainer + models.DB.Where("id IN ?", ids).Find(&containers) + for _, c := range containers { + containerMap[c.ID] = c + } + } + + // 为每个物品计算面包屑 + type ItemWithBreadcrumb struct { + TabWarehouseItem + ContainerBreadcrumb string `json:"ContainerBreadcrumb"` + } + itemsWithBreadcrumb := make([]ItemWithBreadcrumb, len(items)) + for i, item := range items { + itemsWithBreadcrumb[i] = ItemWithBreadcrumb{TabWarehouseItem: item} + if item.ContainerID != nil { + itemsWithBreadcrumb[i].ContainerBreadcrumb = buildContainerBreadcrumb(*item.ContainerID, containerMap) + } } ReturnJson(ctx, "apiOK", gin.H{ "all_count": count, - "items": items, + "items": itemsWithBreadcrumb, "canModifyItems": canModifyItems, }) }) @@ -863,6 +939,24 @@ func ApiWarehouse(r *gin.RouterGroup) { var commits []TabWarehouseItemCommit models.DB.Where("item_id = ?", from.ID).Order("created_at DESC").Find(&commits) + // 为 commits 构建容器面包屑 + type CommitWithBreadcrumb struct { + TabWarehouseItemCommit + OldContainerBreadcrumb string `json:"OldContainerBreadcrumb"` + NewContainerBreadcrumb string `json:"NewContainerBreadcrumb"` + } + commitMap := make(map[uint]TabWarehouseContainer) + commitsWithBreadcrumb := make([]CommitWithBreadcrumb, len(commits)) + for i, c := range commits { + commitsWithBreadcrumb[i] = CommitWithBreadcrumb{TabWarehouseItemCommit: c} + if c.OldContainer != nil { + commitsWithBreadcrumb[i].OldContainerBreadcrumb = buildContainerBreadcrumb(*c.OldContainer, commitMap) + } + if c.NewContainer != nil { + commitsWithBreadcrumb[i].NewContainerBreadcrumb = buildContainerBreadcrumb(*c.NewContainer, commitMap) + } + } + // 关联工单 var woBinds []TabWarehouseItemWorkOrderBind models.DB.Where("item_id = ?", from.ID).Find(&woBinds) @@ -883,9 +977,16 @@ func ApiWarehouse(r *gin.RouterGroup) { ReturnJson(ctx, "apiOK", gin.H{ "item": item, "photos": files, - "commits": commits, + "commits": commitsWithBreadcrumb, "work_orders": workOrders, "canModifyItem": canModifyWarehouse(user.ID, item.CreatorID), + "container_breadcrumb": func() string { + if item.ContainerID == nil { + return "" + } + m := make(map[uint]TabWarehouseContainer) + return buildContainerBreadcrumb(*item.ContainerID, m) + }(), }) }) diff --git a/frontend/ops_vue_js/src/views/warehouse/WarehouseItemDetail.vue b/frontend/ops_vue_js/src/views/warehouse/WarehouseItemDetail.vue index 5cd95c5..8dd9fb3 100644 --- a/frontend/ops_vue_js/src/views/warehouse/WarehouseItemDetail.vue +++ b/frontend/ops_vue_js/src/views/warehouse/WarehouseItemDetail.vue @@ -38,6 +38,7 @@ const notFound = ref(false) // ── 容器名缓存 ── const containerNames = reactive({}) +const containerBreadcrumb = ref('') // ── Tab ── const activeTab = ref('work_orders') @@ -112,6 +113,7 @@ async function fetchItem() { commits.value = data.commits ?? [] workOrders.value = data.work_orders ?? [] canModifyItem.value = data.canModifyItem === true + containerBreadcrumb.value = data.container_breadcrumb ?? '' loadContainerNames() } else { notFound.value = true @@ -375,12 +377,13 @@ onMounted(() => { {{ t('warehouse.quantity') }}: {{ item.Quantity }} {{ t('warehouse.location') }}: - {{ containerNames[item.ContainerID] || `#${item.ContainerID}` }} + {{ containerBreadcrumb }} + {{ `#${item.ContainerID}` }} {{ t('warehouse.unstored') }} @@ -499,9 +502,9 @@ onMounted(() => { {{ fmtTs(commit.CreatedAt) }}
- {{ getContainerName(commit.OldContainer) }} + {{ commit.OldContainerBreadcrumb || t('warehouse.unstored') }} - {{ getContainerName(commit.NewContainer) }} + {{ commit.NewContainerBreadcrumb || t('warehouse.unstored') }}

{{ commit.Remark }}

@@ -526,12 +529,13 @@ onMounted(() => { {{ t('warehouse.current_location') }}: - {{ containerNames[item.ContainerID] || `#${item.ContainerID}` }} + {{ containerBreadcrumb }} + #{{ item.ContainerID }} {{ t('warehouse.unstored') }} diff --git a/frontend/ops_vue_js/src/views/warehouse/WarehouseItemList.vue b/frontend/ops_vue_js/src/views/warehouse/WarehouseItemList.vue index b54faa7..e5b4210 100644 --- a/frontend/ops_vue_js/src/views/warehouse/WarehouseItemList.vue +++ b/frontend/ops_vue_js/src/views/warehouse/WarehouseItemList.vue @@ -29,67 +29,11 @@ const currentPage = ref(1) const search = ref('') const loading = ref(false) -// 容器名映射表 -const containerMap = ref({}) -const allContainerCount = ref(0) - -const isEn = computed(() => locale.value === 'en') - -// ── 统计数据 ── -const stats = reactive({ - total: 0, - inContainer: 0, - unstored: 0, -}) - -// ── 分页信息 ── -const totalPages = computed(() => Math.ceil(totalCount.value / pageSize.value) || 1) - -function getContainerTitle(cid) { - if (cid == null) return `${t('warehouse.unstored_items')}` - return containerMap.value[cid] || `#${cid}` -} - // ── 权限判断 ── function canModifyItem(idx) { return canModifyItems.value[idx] === true } -// ── 获取容器名映射 ── -async function fetchContainerMap() { - try { - const { errCode, data } = await warehouseApi.getContainers({ entries: 500, page: 1 }) - if (errCode === 0 && data) { - allContainerCount.value = data.all_count || 0 - const map = {} - for (const c of (data.containers || [])) { - map[c.ID] = c.Title - } - for (const c of (data.containers || [])) { - if (c.ChildCount > 0) { - await fetchChildContainers(c.ID, map) - } - } - containerMap.value = map - } - } catch { - // ignore - } -} - -async function fetchChildContainers(parentId, map) { - try { - const { errCode, data } = await warehouseApi.getContainers({ entries: 500, page: 1, parent_id: parentId }) - if (errCode === 0 && data) { - for (const c of (data.containers || [])) { - map[c.ID] = c.Title - } - } - } catch { - // ignore - } -} - // ── 获取物品列表 ── async function fetchItems() { loading.value = true @@ -205,9 +149,7 @@ function formatDate(dateStr) { } } -onMounted(() => { - fetchContainerMap().then(fetchItems) -}) +onMounted(fetchItems)