chore: 批量完成项目多模块迭代优化
1. 废弃半成品库存表并统一库存主表 2. 修复列表排序与搜索大小写不敏感问题 3. 新增用户最近登录时间、工单BOM名称字段 4. 完善角色管理、工位选择器功能 5. 增加拧紧数据补录、成品自动回流WMS能力 6. 统一导出时间范围校验规则 7. 丰富物料/备料单筛选条件 8. 调整菜单与权限命名适配产品型号业务
This commit is contained in:
@@ -46,7 +46,8 @@ type FlowVO struct {
|
||||
}
|
||||
|
||||
// ListFlows 查询工艺流程(可按工位号过滤:命中绑定该工位或主工序号的流程)
|
||||
func (s *Service) ListFlows(ctx context.Context, stationNo int) ([]*FlowVO, error) {
|
||||
// page>0 时真分页返回 map{total,list,page,pageSize}(管理页用);page=0 全量数组(工位终端兼容)
|
||||
func (s *Service) ListFlows(ctx context.Context, stationNo, page, pageSize int) (any, error) {
|
||||
q := s.ctx.EntClient.ProcessFlow.Query().
|
||||
Order(ent.Asc(processflow.FieldProcessCode), ent.Asc(processflow.FieldID))
|
||||
flows, err := q.All(ctx)
|
||||
@@ -85,6 +86,18 @@ func (s *Service) ListFlows(ctx context.Context, stationNo int) ([]*FlowVO, erro
|
||||
}
|
||||
out = append(out, vo)
|
||||
}
|
||||
if page > 0 {
|
||||
total := len(out)
|
||||
start := (page - 1) * pageSize
|
||||
if start > total {
|
||||
start = total
|
||||
}
|
||||
end := start + pageSize
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
return map[string]any{"total": total, "list": out[start:end], "page": page, "pageSize": pageSize}, nil
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -95,8 +108,10 @@ func (s *Service) SaveFlow(ctx context.Context, req FlowReq, operator string) er
|
||||
if req.Name == "" {
|
||||
return errors.New("流程名称必填")
|
||||
}
|
||||
if req.StationNo < 1 || req.StationNo > 12 {
|
||||
return errors.New("请选择主工序编号(1~12)")
|
||||
// 工序编号与物理工位解耦:工序是流程步骤编号(1~999,流程内唯一即可),
|
||||
// 工位对应关系由「关联工位」页维护(2026-09-08)
|
||||
if req.StationNo < 1 || req.StationNo > 999 {
|
||||
return errors.New("主工序编号应为 1~999 的整数")
|
||||
}
|
||||
// 解析绑定工位列表:显式 stations 优先,否则回退到 StationNo(兼容旧调用)
|
||||
bindStations := req.Stations
|
||||
@@ -122,21 +137,8 @@ func (s *Service) SaveFlow(ctx context.Context, req FlowReq, operator string) er
|
||||
if status != "ACTIVE" && status != "INACTIVE" {
|
||||
return errors.New("非法状态")
|
||||
}
|
||||
// 校验:绑定工位不得已被其他"启用"流程占用(一个工位只能绑一个启用流程)
|
||||
bound, err := s.ctx.EntClient.Station.Query().
|
||||
Where(station.StationNoIn(stations...), station.FlowIdGT(0)).All(ctx)
|
||||
if err == nil {
|
||||
flowID := req.Id
|
||||
for _, st := range bound {
|
||||
if flowID > 0 && st.FlowId == flowID {
|
||||
continue // 绑定的是本流程自身,允许
|
||||
}
|
||||
other, gErr := s.ctx.EntClient.ProcessFlow.Get(ctx, st.FlowId)
|
||||
if gErr == nil && other.Status == "ACTIVE" {
|
||||
return fmt.Errorf("工位 %d 已被启用流程「%s」绑定,请先在流程/工位中解除绑定", st.StationNo, other.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 绑定语义(2026-09-08 定稿):直接更换——一个工位只有一条关联数据,
|
||||
// 保存时所选工位一律改绑到本流程(覆盖旧绑定),不再报"已被启用流程绑定"冲突。
|
||||
var flowID int
|
||||
if req.Id > 0 {
|
||||
upd := s.ctx.EntClient.ProcessFlow.UpdateOneID(req.Id).
|
||||
@@ -395,7 +397,8 @@ type WorkloadRow struct {
|
||||
NgCount int `json:"ngCount"`
|
||||
}
|
||||
|
||||
func (s *Service) Workload(ctx context.Context, operator, stationNo, from, to string) (map[string]any, error) {
|
||||
func (s *Service) Workload(ctx context.Context, operator, stationNo, from, to string,
|
||||
opPage, opSize, stPage, stSize, detPage, detSize int) (map[string]any, error) {
|
||||
q := s.ctx.EntClient.WorkpieceProcess.Query()
|
||||
if operator != "" {
|
||||
q = q.Where(workpieceprocess.Operator(operator))
|
||||
@@ -449,5 +452,67 @@ func (s *Service) Workload(ctx context.Context, operator, stationNo, from, to st
|
||||
}
|
||||
return list[i].ProcessCode < list[j].ProcessCode
|
||||
})
|
||||
return map[string]any{"rows": list, "detail": rows}, nil
|
||||
|
||||
// 三个视图分别聚合(2026-09-08 绩效报表改造:按人/按工位/明细,各自真分页)
|
||||
byOpAgg := map[string]*WorkloadRow{}
|
||||
byStAgg := map[string]*WorkloadRow{}
|
||||
for _, v := range list {
|
||||
opKey := v.Operator
|
||||
if o, ok := byOpAgg[opKey]; ok {
|
||||
o.DoneCount += v.DoneCount; o.OkCount += v.OkCount; o.NgCount += v.NgCount
|
||||
} else {
|
||||
byOpAgg[opKey] = &WorkloadRow{Operator: v.Operator, DoneCount: v.DoneCount, OkCount: v.OkCount, NgCount: v.NgCount}
|
||||
}
|
||||
stKey := v.StationNo
|
||||
if o, ok := byStAgg[stKey]; ok {
|
||||
o.DoneCount += v.DoneCount; o.OkCount += v.OkCount; o.NgCount += v.NgCount
|
||||
} else {
|
||||
byStAgg[stKey] = &WorkloadRow{StationNo: v.StationNo, DoneCount: v.DoneCount, OkCount: v.OkCount, NgCount: v.NgCount}
|
||||
}
|
||||
}
|
||||
paginateRows := func(all []*ent.WorkpieceProcess, page, size int) (int, []*ent.WorkpieceProcess) {
|
||||
total := len(all)
|
||||
start := (page - 1) * size
|
||||
if start > total {
|
||||
start = total
|
||||
}
|
||||
end := start + size
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
return total, all[start:end]
|
||||
}
|
||||
paginate := func(all []*WorkloadRow, page, size int) (int, []*WorkloadRow) {
|
||||
total := len(all)
|
||||
start := (page - 1) * size
|
||||
if start > total {
|
||||
start = total
|
||||
}
|
||||
end := start + size
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
return total, all[start:end]
|
||||
}
|
||||
|
||||
byOpList := make([]*WorkloadRow, 0, len(byOpAgg))
|
||||
for _, v := range byOpAgg {
|
||||
byOpList = append(byOpList, v)
|
||||
}
|
||||
sort.Slice(byOpList, func(i, j int) bool { return byOpList[i].Operator < byOpList[j].Operator })
|
||||
byStList := make([]*WorkloadRow, 0, len(byStAgg))
|
||||
for _, v := range byStAgg {
|
||||
byStList = append(byStList, v)
|
||||
}
|
||||
sort.Slice(byStList, func(i, j int) bool { return byStList[i].StationNo < byStList[j].StationNo })
|
||||
|
||||
opTotal, byOpPage := paginate(byOpList, opPage, opSize)
|
||||
stTotal, byStPage := paginate(byStList, stPage, stSize)
|
||||
detTotal, detRowsPage := paginateRows(rows, detPage, detSize)
|
||||
|
||||
return map[string]any{
|
||||
"byOperator": map[string]any{"total": opTotal, "list": byOpPage},
|
||||
"byStation": map[string]any{"total": stTotal, "list": byStPage},
|
||||
"detail": map[string]any{"total": detTotal, "list": detRowsPage},
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user