feat: 装配线看板修正、统一密钥Hardman_2026、操作日志追溯、日志按天存储

Dashboard 移除 CNC/清洗机等不存在设备,改为纯装配线看板(扫码枪+拧紧枪+人工);JWT/内部token统一为 Hardman_2026 写入各 etc/*.yaml,MES 建表 DSN 改读 yaml;event_log 增加 workOrderNo/operator,BOM/备料/PLC下发/拧紧/扫码报工/半成品/AGV 全链路埋点,日志页支持工单号/操作人筛选;MES/WMS 日志按天存储(dailyWriter),WMS SetWriter 用 logx.NewWriter 适配
This commit is contained in:
SunYF
2026-08-28 09:22:19 +08:00
parent a2afd2f6dc
commit 450a094f0e
39 changed files with 516 additions and 2111 deletions
@@ -7,6 +7,7 @@ import (
"time"
"bj_power_mes/ent/agvtask"
"bj_power_mes/internal/eventbus"
"bj_power_mes/internal/sse"
"bj_power_mes/internal/svc"
"bj_power_mes/internal/types"
@@ -81,6 +82,16 @@ func (l *AgvTaskLogic) AgvTaskCreate(req *types.AgvTaskCreateReq) (map[string]an
return nil, err
}
// 操作日志(AGV 搬运可追溯)
l.svcCtx.EventBus.Publish(l.ctx, eventbus.NewProductionEvent(
eventbus.EventAgvTaskCreated,
fmt.Sprintf("AGV 任务 %s %s→%s [%s]", taskNo, req.DockFrom, req.DockTo, status),
map[string]any{
"orderNo": req.OrderNo, "taskNo": taskNo, "status": status,
"dockFrom": req.DockFrom, "dockTo": req.DockTo,
"operator": CurrentUserName(l.ctx, l.svcCtx),
}))
if status == "执行中" && sim {
go func(id int, orderNo string) {
time.Sleep(10 * time.Second)
+14 -1
View File
@@ -2,9 +2,11 @@ package production
import (
"context"
"fmt"
"bj_power_mes/ent"
"bj_power_mes/ent/bomitem"
"bj_power_mes/internal/eventbus"
"bj_power_mes/internal/svc"
"bj_power_mes/internal/types"
@@ -81,5 +83,16 @@ func (l *BomLogic) BomSave(req *types.BomSaveReq) error {
return err
}
}
return tx.Commit()
if err := tx.Commit(); err != nil {
return err
}
// 操作日志(BOM 维护可追溯)
l.svcCtx.EventBus.Publish(l.ctx, eventbus.NewProductionEvent(
eventbus.EventBomSaved,
fmt.Sprintf("保存产品 %s 的 BOM%d 项物料)", req.ProductCode, len(req.Items)),
map[string]any{
"productCode": req.ProductCode, "itemCount": len(req.Items),
"operator": CurrentUserName(l.ctx, l.svcCtx),
}))
return nil
}
@@ -7,6 +7,7 @@ import (
"bj_power_mes/ent/materialrequest"
"bj_power_mes/ent/workorder"
"bj_power_mes/internal/eventbus"
"bj_power_mes/internal/svc"
"bj_power_mes/internal/types"
wmsstock "bj_power_mes/internal/wmsstock"
@@ -128,6 +129,20 @@ func (l *MaterialRequestLogic) MaterialRequestCreate(req *types.MaterialRequestC
if err != nil {
return nil, err
}
// 操作日志(备料可追溯)
operator := req.Operator
if operator == "" {
operator = CurrentUserName(l.ctx, l.svcCtx)
}
l.svcCtx.EventBus.Publish(l.ctx, eventbus.NewProductionEvent(
eventbus.EventMaterialRequested,
fmt.Sprintf("备料 %s%s),物料 %d 项", req.OrderNo, status, len(result.Items)),
map[string]any{
"orderNo": req.OrderNo, "status": status, "allOk": result.AllOk,
"operator": operator,
}))
out := map[string]any{"record": rec}
if respText != "" {
out["warn"] = respText
@@ -2,9 +2,11 @@ package production
import (
"context"
"fmt"
"bj_power_mes/ent"
"bj_power_mes/ent/plcsendlog"
"bj_power_mes/internal/eventbus"
"bj_power_mes/internal/plcproc"
"bj_power_mes/internal/sse"
"bj_power_mes/internal/svc"
@@ -29,6 +31,14 @@ func (l *PlcLogic) PlcSendProcess(req *types.PlcSendProcessReq) (*ent.PlcSendLog
if err != nil {
return nil, err
}
// 操作日志
l.svcCtx.EventBus.Publish(l.ctx, eventbus.NewProductionEvent(
eventbus.EventPlcProcessSent,
fmt.Sprintf("PLC 下发工序号 %s → %s", req.CodeStr, req.OrderNo),
map[string]any{
"orderNo": req.OrderNo, "codeStr": req.CodeStr,
"operator": CurrentUserName(l.ctx, l.svcCtx),
}))
l.svcCtx.SSEHandler.Emit(sse.EventDashboardUpdate, `{"type":"plc_sent","orderNo":"`+req.OrderNo+`","code":"`+req.CodeStr+`"}`)
return rec, nil
}
@@ -2,10 +2,12 @@ package production
import (
"context"
"fmt"
"strconv"
"bj_power_mes/ent/processdict"
"bj_power_mes/ent/scanrecord"
"bj_power_mes/internal/eventbus"
"bj_power_mes/internal/sse"
"bj_power_mes/internal/svc"
"bj_power_mes/internal/types"
@@ -58,6 +60,19 @@ func (l *ScanLogic) ScanReport(req *types.ScanReportReq) (map[string]any, error)
return nil, err
}
operator := req.Operator
if operator == "" {
operator = CurrentUserName(l.ctx, l.svcCtx)
}
// 操作日志(工单/工件/步骤/人员可追溯)
l.svcCtx.EventBus.Publish(l.ctx, eventbus.NewProductionEvent(
eventbus.EventScanReported,
fmt.Sprintf("扫码报工[%s] 工序%s 工件%s", action, req.StepCode, req.Sn),
map[string]any{
"orderNo": req.OrderNo, "sn": req.Sn, "stepCode": req.StepCode,
"action": action, "dockCode": req.DockCode, "operator": operator,
}))
l.svcCtx.SSEHandler.Emit(sse.EventDashboardUpdate,
map[string]any{
"type": "scan_reported", "orderNo": req.OrderNo, "sn": req.Sn,
@@ -6,6 +6,7 @@ import (
"strings"
"bj_power_mes/ent/semiflow"
"bj_power_mes/internal/eventbus"
"bj_power_mes/internal/sse"
"bj_power_mes/internal/svc"
"bj_power_mes/internal/types"
@@ -85,6 +86,14 @@ func (l *SemiFlowLogic) record(action string, req *types.SemiFlowReq, zone strin
if err != nil {
return nil, err
}
// 操作日志(半成品流转可追溯)
l.svcCtx.EventBus.Publish(l.ctx, eventbus.NewProductionEvent(
eventbus.EventSemiFlow,
fmt.Sprintf("半成品%s 工件%s → %s", map[string]string{"inbound": "入库", "outbound": "出库"}[action], req.Sn, zone),
map[string]any{
"sn": req.Sn, "orderNo": req.OrderNo, "action": action,
"zoneCode": zone, "completedProcess": req.CompletedProcess, "operator": req.Operator,
}))
l.svcCtx.SSEHandler.Emit(sse.EventDashboardUpdate,
map[string]any{"type": "semi_flow", "action": action, "sn": req.Sn, "orderNo": req.OrderNo})
return map[string]any{"record": rec}, nil
@@ -2,8 +2,10 @@ package production
import (
"context"
"fmt"
"bj_power_mes/ent/torquerecord"
"bj_power_mes/internal/eventbus"
"bj_power_mes/internal/sse"
"bj_power_mes/internal/svc"
"bj_power_mes/internal/types"
@@ -60,6 +62,15 @@ func (l *TorqueLogic) TorqueReport(req *types.TorqueReportReq) (map[string]any,
return nil, err
}
saved++
// 操作日志(拧紧结果可追溯)
l.svcCtx.EventBus.Publish(l.ctx, eventbus.NewProductionEvent(
eventbus.EventTorqueReported,
fmt.Sprintf("拧紧上报 %s 螺栓%s %s 扭矩%.1f°角度%.1f", rec.Sn, rec.ScrewNo, result, rec.Torque, rec.Angle),
map[string]any{
"workOrderNo": rec.WorkOrderNo, "sn": rec.Sn, "dockCode": rec.DockCode,
"screwNo": rec.ScrewNo, "result": result, "operator": rec.Operator,
}))
}
l.svcCtx.SSEHandler.Emit(sse.EventDashboardUpdate,
@@ -46,6 +46,12 @@ func (l *QueryEventLogsLogic) QueryEventLogs(req *types.QueryEventLogsReq) (resp
if req.WorkpieceNo != "" {
conditions = append(conditions, enteventlog.WorkpieceNoContains(req.WorkpieceNo))
}
if req.WorkOrderNo != "" {
conditions = append(conditions, enteventlog.WorkOrderNoContains(req.WorkOrderNo))
}
if req.Operator != "" {
conditions = append(conditions, enteventlog.OperatorContains(req.Operator))
}
if req.JobId > 0 {
conditions = append(conditions, enteventlog.JobId(req.JobId))
}
@@ -87,6 +93,8 @@ func (l *QueryEventLogsLogic) QueryEventLogs(req *types.QueryEventLogsReq) (resp
CreatedAt: lg.CreatedAt.Format(time.RFC3339),
JobId: int(lg.JobId),
WorkpieceNo: lg.WorkpieceNo,
WorkOrderNo: lg.WorkOrderNo,
Operator: lg.Operator,
EquipmentId: int(lg.EquipmentId),
EquipmentName: lg.EquipmentName,
TempSlotNo: int(lg.TempSlotNo),