From 98dfa3ac02fd2bafb09f6d001d711769aef84407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=96=87=E5=B3=B0?= Date: Wed, 29 Apr 2026 18:35:34 +0800 Subject: [PATCH] up --- .workbuddy/memory/2026-04-29.md | 38 ++++++----- backend/my_work/routers/apiWarehouse.go | 65 ++++++++++++++++++- backend/my_work/routers/apiWorkOrder.go | 51 ++++++++++++++- frontend/ops_vue_js/src/i18n/en.json | 6 +- frontend/ops_vue_js/src/i18n/zh-CN.json | 6 +- .../src/views/warehouse/WarehouseAddItem.vue | 8 +-- .../warehouse/WarehouseContainerDetail.vue | 33 +++++++++- .../src/views/warehouse/WarehouseItemEdit.vue | 29 +++++---- .../src/views/warehouse/WarehouseItemList.vue | 29 ++++++++- .../src/views/work_order/AddEditWorkOrder.vue | 16 ++--- .../src/views/work_order/ShowWorkOrder.vue | 6 +- .../src/views/work_order/WorkOrderList.vue | 20 +++++- 12 files changed, 249 insertions(+), 58 deletions(-) diff --git a/.workbuddy/memory/2026-04-29.md b/.workbuddy/memory/2026-04-29.md index 54987b2..8262fd3 100644 --- a/.workbuddy/memory/2026-04-29.md +++ b/.workbuddy/memory/2026-04-29.md @@ -1,23 +1,29 @@ # 2026-04-29 工作日志 -## 完成的工作 +## 仓库物品列表添加列 -### 1. 客户详情页添加编辑按钮 -- 文件: `frontend/ops_vue_js/src/views/customer/CustomerDetail.vue` -- 功能: 根据后端返回的 `canModify` 字段显示/隐藏编辑按钮 -- 权限逻辑: 创建者或客户管理员可编辑 +在仓库容器详情页的物品列表中,在"数量"列后面添加了"工单数量"和"关联客户"两列。 -### 2. 操作日志功能 -- 后端 API: `backend/my_work/routers/apiSysAdmin.go` - - 新增 `/operation_logs` 接口,聚合所有模块的操作日志 - - 支持按模块筛选: all/customer/purchase/schedule/warehouse/work_order - - 支持分页,最新日志在前 +### 修改内容 -- 前端组件: `frontend/ops_vue_js/src/views/sysadmin/OperationLogsTab.vue` - - 左侧模块选择器,右侧日志表格 - - 分页显示,最新日志在前 +**后端** (`backend/my_work/routers/apiWarehouse.go`): +- 修改 `/list_item` API,批量查询物品的工单绑定数量和客户关联信息 +- 新增返回字段:`WorkOrderCount` (int) 和 `Customers` (数组) -- 系统管理页面: `frontend/ops_vue_js/src/views/sysadmin/SysAdminView.vue` - - 新增"操作日志"标签页 +**前端** (`frontend/ops_vue_js/src/views/warehouse/WarehouseContainerDetail.vue`): +- 导入 `IconTool`, `IconUser` 图标和 `RouterLink` 组件 +- 表格表头添加两列:工单数量、关联客户 +- 表格数据行显示: + - 工单数量:橙色徽章显示,带工具图标 + - 关联客户:蓝色标签显示客户姓名,可点击跳转,最多显示3个 +- 更新 colspan 从 8 改为 10 -- 翻译文件: 添加了 `operation_logs` 相关翻译键 +**i18n 翻译**: +- `en.json`: 添加 `work_order.work_order_count` 和 `customer.related_customers` +- `zh-CN.json`: 添加对应中文翻译 +- **修复**: 修正了重复添加 `customer` 对象的问题,将 `related_customers` 合并到已有的 `customer` 对象中 + +### 技术细节 +- 工单数量通过 `TabWarehouseItemWorkOrderBind` 表统计 +- 客户信息通过 `TabWarehouseItemCustomerBind` 和 `TabCustomer` 表关联查询 +- 采用批量查询优化性能,避免N+1查询问题 diff --git a/backend/my_work/routers/apiWarehouse.go b/backend/my_work/routers/apiWarehouse.go index 9e59ac3..3836c7b 100644 --- a/backend/my_work/routers/apiWarehouse.go +++ b/backend/my_work/routers/apiWarehouse.go @@ -902,14 +902,73 @@ func ApiWarehouse(r *gin.RouterGroup) { } } - // 为每个物品计算面包屑 + // 收集所有物品ID + itemIDs := make([]uint, 0, len(items)) + for _, item := range items { + itemIDs = append(itemIDs, item.ID) + } + + // 批量查询工单绑定数量 + workOrderCounts := make(map[uint]int) + if len(itemIDs) > 0 { + var woBinds []TabWarehouseItemWorkOrderBind + models.DB.Where("item_id IN ?", itemIDs).Find(&woBinds) + for _, bind := range woBinds { + workOrderCounts[bind.ItemID]++ + } + } + + // 批量查询客户关联 + type CustomerInfo struct { + ID uint `json:"id"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Title string `json:"title"` + } + itemCustomers := make(map[uint][]CustomerInfo) + if len(itemIDs) > 0 { + var customerBinds []TabWarehouseItemCustomerBind + models.DB.Where("item_id IN ?", itemIDs).Find(&customerBinds) + customerIDs := make([]uint, 0) + for _, bind := range customerBinds { + customerIDs = append(customerIDs, bind.CustomerID) + } + // 查询客户信息 + customerMap := make(map[uint]TabCustomer) + if len(customerIDs) > 0 { + var customers []TabCustomer + models.DB.Where("id IN ?", customerIDs).Find(&customers) + for _, c := range customers { + customerMap[c.ID] = c + } + } + // 构建物品ID到客户列表的映射 + for _, bind := range customerBinds { + if c, ok := customerMap[bind.CustomerID]; ok { + itemCustomers[bind.ItemID] = append(itemCustomers[bind.ItemID], CustomerInfo{ + ID: c.ID, + FirstName: c.FirstName, + LastName: c.LastName, + Title: c.Title, + }) + } + } + } + + // 为每个物品计算面包屑并添加额外信息 type ItemWithBreadcrumb struct { TabWarehouseItem - ContainerBreadcrumb string `json:"ContainerBreadcrumb"` + ContainerBreadcrumb string `json:"ContainerBreadcrumb"` + WorkOrderCount int `json:"WorkOrderCount"` + Customers []CustomerInfo `json:"Customers"` } itemsWithBreadcrumb := make([]ItemWithBreadcrumb, len(items)) for i, item := range items { - itemsWithBreadcrumb[i] = ItemWithBreadcrumb{TabWarehouseItem: item} + itemsWithBreadcrumb[i] = ItemWithBreadcrumb{ + TabWarehouseItem: item, + WorkOrderCount: workOrderCounts[item.ID], + Customers: itemCustomers[item.ID], + } if item.ContainerID != nil { itemsWithBreadcrumb[i].ContainerBreadcrumb = buildContainerBreadcrumb(*item.ContainerID, containerMap) } diff --git a/backend/my_work/routers/apiWorkOrder.go b/backend/my_work/routers/apiWorkOrder.go index b8be3bb..eb58cb5 100644 --- a/backend/my_work/routers/apiWorkOrder.go +++ b/backend/my_work/routers/apiWorkOrder.go @@ -330,9 +330,58 @@ func ApiWorkOrder(r *gin.RouterGroup) { Limit(from.Entries). Find(&orders) + // 定义返回结构 + type CustomerInfo struct { + ID uint `json:"id"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + PrimaryPhone string `json:"primary_phone"` + } + type OrderWithCustomers struct { + TabWorkOrder + Customers []CustomerInfo `json:"customers"` + } + + var ordersWithCustomers []OrderWithCustomers + for _, order := range orders { + orderItem := OrderWithCustomers{ + TabWorkOrder: order, + Customers: []CustomerInfo{}, + } + + // 查询关联客户 + var customerBinds []TabWorkOrderCustomerBind + models.DB.Where("work_order_id = ?", order.ID).Find(&customerBinds) + if len(customerBinds) > 0 { + var customerIDs []uint + for _, b := range customerBinds { + customerIDs = append(customerIDs, b.CustomerID) + } + var customers []TabCustomer + models.DB.Where("id IN ?", customerIDs).Find(&customers) + for _, c := range customers { + customerInfo := CustomerInfo{ + ID: c.ID, + FirstName: c.FirstName, + LastName: c.LastName, + PrimaryPhone: "", + } + // 获取主电话 + var phone TabCustomerPhone + if err := models.DB.Where("customer_id = ? AND is_primary = ?", c.ID, true).First(&phone).Error; err == nil { + customerInfo.PrimaryPhone = phone.Phone + } else if err := models.DB.Where("customer_id = ?", c.ID).First(&phone).Error; err == nil { + customerInfo.PrimaryPhone = phone.Phone + } + orderItem.Customers = append(orderItem.Customers, customerInfo) + } + } + ordersWithCustomers = append(ordersWithCustomers, orderItem) + } + ReturnJson(ctx, "apiOK", gin.H{ "all_count": count, - "all_orders": orders, + "all_orders": ordersWithCustomers, }) }) diff --git a/frontend/ops_vue_js/src/i18n/en.json b/frontend/ops_vue_js/src/i18n/en.json index 2e14ecf..ef99ab5 100644 --- a/frontend/ops_vue_js/src/i18n/en.json +++ b/frontend/ops_vue_js/src/i18n/en.json @@ -174,7 +174,8 @@ "confirm_delete_commit": "Are you sure you want to delete this progress?", "linked_items": "Linked Items", "submit": "Submit", - "save_changes": "Save Changes" + "save_changes": "Save Changes", + "work_order_count": "Work Order Count" }, "warehouse": { "title": "Warehouse", @@ -598,6 +599,7 @@ "detail_title": "Customer Detail", "basic_info": "Basic Information", "created_by": "Created By", - "not_found": "Customer not found" + "not_found": "Customer not found", + "related_customers": "Related Customers" } } diff --git a/frontend/ops_vue_js/src/i18n/zh-CN.json b/frontend/ops_vue_js/src/i18n/zh-CN.json index 44dc747..4e27e17 100644 --- a/frontend/ops_vue_js/src/i18n/zh-CN.json +++ b/frontend/ops_vue_js/src/i18n/zh-CN.json @@ -174,7 +174,8 @@ "confirm_delete_commit": "确定要删除此进度吗?", "linked_items": "关联物品", "submit": "提交", - "save_changes": "保存修改" + "save_changes": "保存修改", + "work_order_count": "工单数量" }, "warehouse": { "title": "仓库", @@ -598,6 +599,7 @@ "detail_title": "客户详情", "basic_info": "基本信息", "created_by": "创建者", - "not_found": "客户不存在" + "not_found": "客户不存在", + "related_customers": "关联客户" } } diff --git a/frontend/ops_vue_js/src/views/warehouse/WarehouseAddItem.vue b/frontend/ops_vue_js/src/views/warehouse/WarehouseAddItem.vue index 476a689..fe9c73a 100644 --- a/frontend/ops_vue_js/src/views/warehouse/WarehouseAddItem.vue +++ b/frontend/ops_vue_js/src/views/warehouse/WarehouseAddItem.vue @@ -255,7 +255,7 @@ async function submit() { -
+
{{ t('message.loading') }}
{{ t('warehouse.linked_customer_not_found') || '未找到客户' }}
diff --git a/frontend/ops_vue_js/src/views/warehouse/WarehouseContainerDetail.vue b/frontend/ops_vue_js/src/views/warehouse/WarehouseContainerDetail.vue index 06a363c..af6a6e4 100644 --- a/frontend/ops_vue_js/src/views/warehouse/WarehouseContainerDetail.vue +++ b/frontend/ops_vue_js/src/views/warehouse/WarehouseContainerDetail.vue @@ -1,6 +1,6 @@