feat: 完成产线MES系统全流程功能迭代与优化
本提交完成了多个核心模块的功能完善与业务对齐: 1. 工位终端:固定工位配置、移除自选工位逻辑、适配配置化工位号 2. MES核心:重构工位组合逻辑、新增工单/流程状态管理、补全报工/追溯逻辑 3. WMS客户端:新增修改密码功能、优化帮助弹窗逻辑 4. 文档与权限:补充完整操作手册、统一菜单名称与权限描述 5. 修复多业务校验:排产数量校验、工单状态校验、工位绑定规则
This commit is contained in:
@@ -5,7 +5,10 @@ import (
|
||||
"errors"
|
||||
|
||||
"bj_power_mes/ent"
|
||||
"bj_power_mes/ent/dailyplan"
|
||||
"bj_power_mes/ent/materialrequest"
|
||||
"bj_power_mes/ent/workorder"
|
||||
"bj_power_mes/ent/workpiece"
|
||||
)
|
||||
|
||||
type WorkOrderReq struct {
|
||||
@@ -37,8 +40,11 @@ func (s *Service) CreateWorkOrder(ctx context.Context, req WorkOrderReq, operato
|
||||
status = "CREATED"
|
||||
}
|
||||
if req.ProcessSeq == "" {
|
||||
req.ProcessSeq = "123456789101112"
|
||||
req.ProcessSeq = FullProcessSeq
|
||||
} else if err := ValidateProcessSeq(req.ProcessSeq); err != nil {
|
||||
return err
|
||||
}
|
||||
req.ProcessSeq = NormalizeProcessSeq(req.ProcessSeq)
|
||||
b := s.ctx.EntClient.WorkOrder.Create().
|
||||
SetWorkOrderNo(req.WorkOrderNo).
|
||||
SetProductTypeId(req.ProductTypeId).
|
||||
@@ -68,8 +74,25 @@ func (s *Service) UpdateWorkOrder(ctx context.Context, req WorkOrderReq, operato
|
||||
if req.Id == 0 {
|
||||
return errors.New("缺少 id")
|
||||
}
|
||||
u := s.ctx.EntClient.WorkOrder.UpdateOneID(req.Id).
|
||||
SetStatus(req.Status).SetQuantity(req.Quantity).SetProcessSeq(req.ProcessSeq)
|
||||
if req.ProcessSeq != "" {
|
||||
if err := ValidateProcessSeq(req.ProcessSeq); err != nil {
|
||||
return err
|
||||
}
|
||||
req.ProcessSeq = NormalizeProcessSeq(req.ProcessSeq)
|
||||
}
|
||||
u := s.ctx.EntClient.WorkOrder.UpdateOneID(req.Id).SetProcessSeq(req.ProcessSeq)
|
||||
if req.Status != "" {
|
||||
u.SetStatus(req.Status)
|
||||
}
|
||||
if req.Quantity > 0 {
|
||||
u.SetQuantity(req.Quantity)
|
||||
}
|
||||
if req.ProductCode != "" {
|
||||
u.SetProductCode(req.ProductCode)
|
||||
}
|
||||
if req.ProductName != "" {
|
||||
u.SetProductName(req.ProductName)
|
||||
}
|
||||
if req.PlanStart != "" {
|
||||
if t, err := parseDate(req.PlanStart); err == nil {
|
||||
u.SetPlanStart(t)
|
||||
@@ -90,8 +113,8 @@ func (s *Service) UpdateWorkOrder(ctx context.Context, req WorkOrderReq, operato
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListWorkOrders 查询工单(支持工单号/状态过滤)
|
||||
func (s *Service) ListWorkOrders(ctx context.Context, orderNo, status string) ([]*ent.WorkOrder, error) {
|
||||
// ListWorkOrders 查询工单(支持工单号/状态/产品编码/产品名称 过滤)
|
||||
func (s *Service) ListWorkOrders(ctx context.Context, orderNo, status, productCode, productName string) ([]*ent.WorkOrder, error) {
|
||||
q := s.ctx.EntClient.WorkOrder.Query()
|
||||
if orderNo != "" {
|
||||
q = q.Where(workorder.WorkOrderNoContains(orderNo))
|
||||
@@ -99,6 +122,12 @@ func (s *Service) ListWorkOrders(ctx context.Context, orderNo, status string) ([
|
||||
if status != "" {
|
||||
q = q.Where(workorder.Status(status))
|
||||
}
|
||||
if productCode != "" {
|
||||
q = q.Where(workorder.ProductCodeContains(productCode))
|
||||
}
|
||||
if productName != "" {
|
||||
q = q.Where(workorder.ProductNameContains(productName))
|
||||
}
|
||||
return q.Order(ent.Desc(workorder.FieldID)).All(ctx)
|
||||
}
|
||||
|
||||
@@ -107,4 +136,57 @@ func (s *Service) GetWorkOrder(ctx context.Context, id int) (*ent.WorkOrder, err
|
||||
return s.ctx.EntClient.WorkOrder.Get(ctx, id)
|
||||
}
|
||||
return s.ctx.EntClient.WorkOrder.Query().Order(ent.Desc(workorder.FieldID)).First(ctx)
|
||||
}
|
||||
|
||||
// 工单状态白名单
|
||||
var workOrderStatuses = map[string]bool{
|
||||
"CREATED": true, "RELEASED": true, "IN_PROGRESS": true, "DONE": true,
|
||||
"PENDING": true, "CONFIRMED": true,
|
||||
}
|
||||
|
||||
// SetWorkOrderStatus 工单状态流转(发布/开工/完工等),操作列快捷操作。
|
||||
func (s *Service) SetWorkOrderStatus(ctx context.Context, id int, status, operator string) error {
|
||||
if id <= 0 {
|
||||
return errors.New("缺少 id")
|
||||
}
|
||||
if !workOrderStatuses[status] {
|
||||
return errors.New("非法的工单状态")
|
||||
}
|
||||
if err := s.ctx.EntClient.WorkOrder.UpdateOneID(id).SetStatus(status).Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if wo, err := s.ctx.EntClient.WorkOrder.Get(ctx, id); err == nil {
|
||||
s.ctx.EventLog.Write(ctx, "work.order.status", wo.WorkOrderNo, operator, "work_order", wo.WorkOrderNo, "变更工单状态", map[string]any{"status": status})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteWorkOrder 删除工单。
|
||||
// 安全条件:① 状态仅限 已创建/待排产/已发布(未开始生产);② 无日排产记录;
|
||||
// ③ 未生成备料单;④ 无任何工件生产数据。
|
||||
func (s *Service) DeleteWorkOrder(ctx context.Context, id int, operator string) error {
|
||||
if id <= 0 {
|
||||
return errors.New("缺少 id")
|
||||
}
|
||||
wo, err := s.ctx.EntClient.WorkOrder.Get(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("工单不存在")
|
||||
}
|
||||
if wo.Status != "CREATED" && wo.Status != "PENDING" && wo.Status != "RELEASED" {
|
||||
return errors.New("仅「已创建 / 待排产 / 已发布」状态的工单可删除,生产中或已完成的工单不能删除")
|
||||
}
|
||||
if n, err := s.ctx.EntClient.DailyPlan.Query().Where(dailyplan.OrderNo(wo.WorkOrderNo)).Count(ctx); err == nil && n > 0 {
|
||||
return errors.New("该工单已有日排产记录,请先删除对应排产后再删除工单")
|
||||
}
|
||||
if n, err := s.ctx.EntClient.MaterialRequest.Query().Where(materialrequest.OrderNo(wo.WorkOrderNo)).Count(ctx); err == nil && n > 0 {
|
||||
return errors.New("该工单已生成备料单,不能删除")
|
||||
}
|
||||
if n, err := s.ctx.EntClient.Workpiece.Query().Where(workpiece.OrderNo(wo.WorkOrderNo)).Count(ctx); err == nil && n > 0 {
|
||||
return errors.New("该工单已有工件生产数据,不能删除")
|
||||
}
|
||||
if err := s.ctx.EntClient.WorkOrder.DeleteOneID(id).Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
s.ctx.EventLog.Write(ctx, "work.order.delete", wo.WorkOrderNo, operator, "work_order", wo.WorkOrderNo, "删除工单", map[string]any{"status": wo.Status})
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user