chore: 批量完成项目多模块迭代优化
1. 废弃半成品库存表并统一库存主表 2. 修复列表排序与搜索大小写不敏感问题 3. 新增用户最近登录时间、工单BOM名称字段 4. 完善角色管理、工位选择器功能 5. 增加拧紧数据补录、成品自动回流WMS能力 6. 统一导出时间范围校验规则 7. 丰富物料/备料单筛选条件 8. 调整菜单与权限命名适配产品型号业务
This commit is contained in:
@@ -22,6 +22,19 @@ type stockKey struct {
|
||||
ZoneCode string
|
||||
QualityStatus string
|
||||
ManageMode int
|
||||
Category int // 品类 1原材料/2半成品/3成品(统一主表收编后加入分组)
|
||||
}
|
||||
|
||||
// categoryLabel 品类中文名
|
||||
func categoryLabel(c int) string {
|
||||
switch c {
|
||||
case invCatSemi:
|
||||
return "半成品"
|
||||
case invCatFinished:
|
||||
return "成品"
|
||||
default:
|
||||
return "原材料"
|
||||
}
|
||||
}
|
||||
|
||||
// stockAggRow 聚合主列表的行结构(按 物料+区域+质量+管理粒度 聚合,只返回数量,不铺开明细)
|
||||
@@ -95,6 +108,7 @@ type aggregateStockArgs struct {
|
||||
ZoneCode string
|
||||
QualityStatus string
|
||||
ManageMode string
|
||||
Category string // 1原材料/2半成品/3成品/空=全部
|
||||
InboundNo string
|
||||
StartDate string
|
||||
EndDate string
|
||||
@@ -128,7 +142,7 @@ func aggregateStock(ctx *svc.ServiceContext, a aggregateStockArgs) ([]*stockAggR
|
||||
))
|
||||
}
|
||||
if a.ZoneCode != "" {
|
||||
q = q.Where(inventory.ZoneCodeEQ(a.ZoneCode))
|
||||
q = q.Where(inventory.ZoneCodeEqualFold(a.ZoneCode))
|
||||
}
|
||||
if a.QualityStatus != "" {
|
||||
q = q.Where(inventory.QualityStatusEQ(a.QualityStatus))
|
||||
@@ -141,6 +155,13 @@ func aggregateStock(ctx *svc.ServiceContext, a aggregateStockArgs) ([]*stockAggR
|
||||
} else if a.ManageMode == "2" {
|
||||
q = q.Where(inventory.ManageModeEQ(2))
|
||||
}
|
||||
if a.Category == "1" {
|
||||
q = q.Where(inventory.CategoryEQ(invCatRaw))
|
||||
} else if a.Category == "2" {
|
||||
q = q.Where(inventory.CategoryEQ(invCatSemi))
|
||||
} else if a.Category == "3" {
|
||||
q = q.Where(inventory.CategoryEQ(invCatFinished))
|
||||
}
|
||||
// 时间筛选:默认近3个月
|
||||
startUnix := int64(0)
|
||||
if a.StartDate != "" {
|
||||
@@ -206,7 +227,7 @@ func aggregateStock(ctx *svc.ServiceContext, a aggregateStockArgs) ([]*stockAggR
|
||||
if zc == "" {
|
||||
zc = "未分区"
|
||||
}
|
||||
key := stockKey{inv.MaterialCode, zc, inv.QualityStatus, inv.ManageMode}
|
||||
key := stockKey{inv.MaterialCode, zc, inv.QualityStatus, inv.ManageMode, inv.Category}
|
||||
g, ok := group[key]
|
||||
if !ok {
|
||||
g = &agg{}
|
||||
@@ -279,6 +300,7 @@ type materialAggRow struct {
|
||||
MaterialName string `json:"materialName"`
|
||||
Spec string `json:"spec"`
|
||||
ManageMode int `json:"manageMode"` // 1结构件/2精密件
|
||||
Category int `json:"category"` // 品类 1原材料/2半成品/3成品
|
||||
TotalQty int `json:"totalQty"` // 总数量(结构件=数量求和;精密件=SN 行数)
|
||||
LockedQty int `json:"lockedQty"` // 锁定量
|
||||
AvailQty int `json:"availQty"` // 可用量 = total - locked
|
||||
@@ -299,6 +321,7 @@ type materialSummaryArgs struct {
|
||||
MaterialCode string
|
||||
MaterialName string
|
||||
ManageMode string
|
||||
Category string // 1原材料/2半成品/3成品/空=全部
|
||||
Page int
|
||||
PageSize int
|
||||
}
|
||||
@@ -341,6 +364,13 @@ func aggregateMaterialSummary(ctx *svc.ServiceContext, a materialSummaryArgs) ([
|
||||
} else if a.ManageMode == "2" {
|
||||
q = q.Where(inventory.ManageModeEQ(2))
|
||||
}
|
||||
if a.Category == "1" {
|
||||
q = q.Where(inventory.CategoryEQ(invCatRaw))
|
||||
} else if a.Category == "2" {
|
||||
q = q.Where(inventory.CategoryEQ(invCatSemi))
|
||||
} else if a.Category == "3" {
|
||||
q = q.Where(inventory.CategoryEQ(invCatFinished))
|
||||
}
|
||||
|
||||
all, err := q.Order(ent.Desc("created_at"), ent.Desc("id")).All(ctx0())
|
||||
if err != nil {
|
||||
@@ -378,6 +408,7 @@ func aggregateMaterialSummary(ctx *svc.ServiceContext, a materialSummaryArgs) ([
|
||||
qPending int
|
||||
qRejected int
|
||||
mMode int // 管理粒度(同物料唯一,取首见行的值)
|
||||
mCategory int // 品类(同物料唯一,取首见行的值)
|
||||
batchCnt int
|
||||
snCnt int
|
||||
zones []string
|
||||
@@ -391,7 +422,7 @@ func aggregateMaterialSummary(ctx *svc.ServiceContext, a materialSummaryArgs) ([
|
||||
key := inv.MaterialCode
|
||||
g, ok := group[key]
|
||||
if !ok {
|
||||
g = &agg{mMode: inv.ManageMode, zoneSeen: map[string]bool{}}
|
||||
g = &agg{mMode: inv.ManageMode, mCategory: inv.Category, zoneSeen: map[string]bool{}}
|
||||
group[key] = g
|
||||
order = append(order, key)
|
||||
}
|
||||
@@ -454,6 +485,7 @@ func aggregateMaterialSummary(ctx *svc.ServiceContext, a materialSummaryArgs) ([
|
||||
MaterialName: name,
|
||||
Spec: matSpec[code],
|
||||
ManageMode: g.mMode,
|
||||
Category: g.mCategory,
|
||||
TotalQty: g.totalQty,
|
||||
LockedQty: g.lockedQty,
|
||||
AvailQty: g.totalQty - g.lockedQty,
|
||||
@@ -492,6 +524,7 @@ func stockDetailsHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
}
|
||||
qualityStatus := r.URL.Query().Get("qualityStatus")
|
||||
manageMode := atoi(r.URL.Query().Get("manageMode"), 0)
|
||||
category := atoi(r.URL.Query().Get("category"), 0)
|
||||
page := atoi(r.URL.Query().Get("page"), 1)
|
||||
pageSize := atoi(r.URL.Query().Get("pageSize"), 50)
|
||||
|
||||
@@ -499,10 +532,10 @@ func stockDetailsHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
q = q.Where(inventory.StatusIn("在库", "锁定"))
|
||||
q = q.Where(inventory.Or(inventory.ManageModeEQ(2), inventory.QuantityGT(0)))
|
||||
if materialCode != "" {
|
||||
q = q.Where(inventory.MaterialCodeEQ(materialCode))
|
||||
q = q.Where(inventory.MaterialCodeEqualFold(materialCode))
|
||||
}
|
||||
if zoneCode != "" {
|
||||
q = q.Where(inventory.ZoneCodeEQ(zoneCode))
|
||||
q = q.Where(inventory.ZoneCodeEqualFold(zoneCode))
|
||||
}
|
||||
if qualityStatus != "" {
|
||||
q = q.Where(inventory.QualityStatusEQ(qualityStatus))
|
||||
@@ -510,6 +543,9 @@ func stockDetailsHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
if manageMode != 0 {
|
||||
q = q.Where(inventory.ManageModeEQ(manageMode))
|
||||
}
|
||||
if category != 0 {
|
||||
q = q.Where(inventory.CategoryEQ(category))
|
||||
}
|
||||
|
||||
total, err := q.Count(ctx0())
|
||||
if err != nil {
|
||||
@@ -588,6 +624,11 @@ func exportStockHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
sendExcel(w, xlsxFilename("物料汇总"), headers, matrix)
|
||||
return
|
||||
}
|
||||
startDate, endDate, rerr := normalizeExportRange(r.URL.Query().Get("startDate"), r.URL.Query().Get("endDate"))
|
||||
if rerr != nil {
|
||||
fail(w, http.StatusBadRequest, rerr.Error())
|
||||
return
|
||||
}
|
||||
rows, _, err := aggregateStock(ctx, aggregateStockArgs{
|
||||
MaterialCode: r.URL.Query().Get("materialCode"),
|
||||
MaterialName: r.URL.Query().Get("materialName"),
|
||||
@@ -595,8 +636,8 @@ func exportStockHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
QualityStatus: r.URL.Query().Get("qualityStatus"),
|
||||
ManageMode: r.URL.Query().Get("manageMode"),
|
||||
InboundNo: r.URL.Query().Get("inboundNo"),
|
||||
StartDate: r.URL.Query().Get("startDate"),
|
||||
EndDate: r.URL.Query().Get("endDate"),
|
||||
StartDate: startDate,
|
||||
EndDate: endDate,
|
||||
Page: 1,
|
||||
PageSize: 1000000, // 全量
|
||||
})
|
||||
@@ -662,9 +703,17 @@ func buildZoneSummary(ctx *svc.ServiceContext) ([]zoneSummRow, error) {
|
||||
if zc == "" {
|
||||
zc = "未分区"
|
||||
}
|
||||
// 类型标签:批次 / 精密件 / 半成品 / 成品(统一主表收编后按品类细分)
|
||||
t := "批次"
|
||||
if inv.ManageMode == 2 {
|
||||
t = "精密件"
|
||||
switch inv.Category {
|
||||
case invCatSemi:
|
||||
t = "半成品"
|
||||
case invCatFinished:
|
||||
t = "成品"
|
||||
default:
|
||||
t = "精密件"
|
||||
}
|
||||
}
|
||||
key := zc + "|" + inv.QualityStatus + "|" + t
|
||||
g, ok := agg[key]
|
||||
|
||||
Reference in New Issue
Block a user