feat: 新增检测单关联、基础数据优化与入库单升级

1. 新增出库单检测单号字段并添加索引支持溯源
2. 优化基础数据页面物料类型展示与选择逻辑
3. 升级入库单导入功能,支持自动生成单号并返回导入结果
4. 优化接驳台查询排序方式
5. 修复字符串拼接空格问题
This commit is contained in:
SunYF
2026-09-21 15:28:14 +08:00
parent 0e769f3813
commit 12ca493c61
70 changed files with 25782 additions and 119 deletions
+79 -32
View File
@@ -3,6 +3,7 @@ package handler
import (
"fmt"
"net/http"
"strconv"
"time"
"bj_power_wms/ent"
@@ -680,28 +681,18 @@ func inboundNosByType(ctx *svc.ServiceContext, inboundType string) ([]string, er
return nos, nil
}
// pendingInspectionItem 待检清单展开明细行
type pendingInspectionItem struct {
ID int `json:"id"` // inventory.id(真实主键,禁止伪 id)
TargetId string `json:"targetId"` // 批次号或 SN
ManageMode int `json:"manageMode"` // 1结构件/2电气件
ItemType int `json:"itemType"` // 品类 1原材料/2半成品/3成品/4其他(§E:带入录入页判定其他类)
Quantity int `json:"quantity"`
ZoneCode string `json:"zoneCode"`
}
// pendingInspectionRow 待检清单主行(按 入库单 + 物料 分组,§E2)
// 详情明细改为按需分页加载(右侧抽屉),主行只带总数不塞 details 数组,避免 3000 SN 一次进内存
type pendingInspectionRow struct {
InboundNo string `json:"inboundNo"`
InboundType string `json:"inboundType"`
OwnershipType string `json:"ownershipType"`
OwnershipNo string `json:"ownershipNo"`
MaterialCode string `json:"materialCode"`
MaterialName string `json:"materialName"`
UnInspectedQty int `json:"unInspectedQty"` // 未检数量(结构件=数量求和;电气件=SN 行数)
BatchSnCount int `json:"batchSnCount"` // 未检批次数/SN
InboundTime int64 `json:"inboundTime"`
Details []pendingInspectionItem `json:"details"`
InboundNo string `json:"inboundNo"`
InboundType string `json:"inboundType"`
OwnershipType string `json:"ownershipType"`
OwnershipNo string `json:"ownershipNo"`
MaterialCode string `json:"materialCode"`
MaterialName string `json:"materialName"`
UnInspectedQty int `json:"unInspectedQty"` // 未检数量(结构件=数量求和;电气件=SN 行数)
DetailsTotal int `json:"detailsTotal"` // 未检批次数/SN 总数(抽屉分页拉明细)
InboundTime int64 `json:"inboundTime"`
}
// pendingInspectionHandler 待检清单(来料检验问题2):列出 quality_status=未检 的库存行,
@@ -769,9 +760,8 @@ func pendingInspectionHandler(ctx *svc.ServiceContext) http.HandlerFunc {
}
}
// 物料名称/品类 map
// 物料名称 map
matName := map[string]string{}
matItemType := map[string]int{}
codeSet := []string{}
seenC := map[string]bool{}
for _, inv := range all {
@@ -784,7 +774,6 @@ func pendingInspectionHandler(ctx *svc.ServiceContext) http.HandlerFunc {
if mats, e := ctx.EntClient.Material.Query().Where(material.CodeIn(codeSet...)).All(ctx0()); e == nil {
for _, m := range mats {
matName[m.Code] = m.Name
matItemType[m.Code] = m.ItemType
}
}
}
@@ -818,15 +807,7 @@ func pendingInspectionHandler(ctx *svc.ServiceContext) http.HandlerFunc {
qty = inv.Quantity
}
g.UnInspectedQty += qty
g.BatchSnCount++
tid := inv.BatchNo
if inv.ManageMode == 2 {
tid = inv.SnCode
}
g.Details = append(g.Details, pendingInspectionItem{
ID: inv.ID, TargetId: tid, ManageMode: inv.ManageMode, ItemType: matItemType[inv.MaterialCode],
Quantity: inv.Quantity, ZoneCode: inv.ZoneCode,
})
g.DetailsTotal++
if o != nil && o.CreatedAt > g.InboundTime {
g.InboundTime = o.CreatedAt
}
@@ -856,3 +837,69 @@ func strOrEmpty(o *ent.InboundOrder) string {
}
return o.InboundType
}
// pendingDetailsInspectionHandler GET /api/inspection/pending/details
// 待检清单主行抽屉里的明细分页(右侧抽屉懒加载,不再主行带 details 数组)。
// 入参:inboundNo + materialCode + page + pageSize(默认 20)。
func pendingDetailsInspectionHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
inboundNo := q.Get("inboundNo")
materialCode := q.Get("materialCode")
if inboundNo == "" || materialCode == "" {
fail(w, http.StatusBadRequest, "inboundNo 和 materialCode 不能为空")
return
}
page, _ := strconv.Atoi(q.Get("page"))
pageSize, _ := strconv.Atoi(q.Get("pageSize"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 500 {
pageSize = 20
}
qry := svcCtx.EntClient.Inventory.Query().
Where(
inventory.InboundNoEQ(inboundNo),
inventory.MaterialCodeEQ(materialCode),
inventory.QualityStatusEQ("未检"),
)
total, err := qry.Count(ctx0())
if err != nil {
fail(w, http.StatusInternalServerError, err.Error())
return
}
start := (page - 1) * pageSize
list, err := qry.
Order(inventory.ByID()).
Offset(start).
Limit(pageSize).
All(ctx0())
if err != nil {
fail(w, http.StatusInternalServerError, err.Error())
return
}
// itemType 从物料档案补查(一个 materialCode 唯一)
itemType := 0
if m, e := svcCtx.EntClient.Material.Query().Where(material.CodeEQ(materialCode)).Only(ctx0()); e == nil {
itemType = m.ItemType
}
rows := make([]map[string]any, 0, len(list))
for _, inv := range list {
tid := inv.BatchNo
if inv.ManageMode == 2 {
tid = inv.SnCode
}
rows = append(rows, map[string]any{
"targetId": tid,
"manageMode": inv.ManageMode,
"itemType": itemType,
"quantity": inv.Quantity,
"zoneCode": inv.ZoneCode,
"id": inv.ID,
})
}
ok(w, map[string]any{"list": rows, "total": total, "page": page, "pageSize": pageSize})
}
}