refactor: 重构产线工位与备料流程,移除冗余字段
1. 移除工单、工件、日排产中的冗余工位组合/接驳台字段 2. 新增工位接驳台编码字段与唯一约束,关联WMS接驳台主数据 3. 重构日排产为工位产量分配模式,替代原接驳台列表 4. 新增备料单工位级字段与分批出库支持 5. 移除定时同步可生产数量,改为WMS实时拉取接口 6. 过滤操作日志,排除登录/退出相关日志 7. 调整仪表盘工序展示逻辑为今日派工路线 8. 新增接驳台维护菜单与基础数据
This commit is contained in:
@@ -7,35 +7,27 @@ import (
|
||||
"bj_power_wms/internal/svc"
|
||||
)
|
||||
|
||||
// producibleSyncHandler 接收 MES 推送的可生产数量快照 + 未来5天物料需求(X-API-TOKEN 内部接口)
|
||||
//
|
||||
// 业务背景(问题记录 L470-474 + L256):
|
||||
// - 可生产套数 = min(各物料可用量 ÷ 单台用量),BOM 只在 MES、库存只在 WMS,
|
||||
// 由 MES 计算后推送快照,WMS 库存页卡片只读展示(两系统独立运行约束,WMS 不反向依赖 MES)。
|
||||
// 可生产数量(问题记录 L470-474 + L256):
|
||||
// - 可生产套数 = min(各物料可用量 ÷ 单台用量)。BOM 单台用量在 MES、库存可用量在 WMS,
|
||||
// 由 MES 实时计算,WMS 打开本页时按需拉一次(两系统之间不做定时/批量同步)。
|
||||
// - 未来5天需求量 = 近5天日排产 × 物料清单单台用量,是备料四态「预警」判定的数据源。
|
||||
//
|
||||
// 推送语义:全量覆盖(先清后写),单事务提交;MES 侧每次重算后整体推送一次。
|
||||
func producibleSyncHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
// 拉取语义:每次查询先实时取 MES 结果,再全量覆盖本地快照(单事务),保证展示与 MES 当前口径一致。
|
||||
|
||||
// queryProducibleHandler GET /api/stock/producible 可生产数量(实时拉取 MES 后落快照再返回)
|
||||
func queryProducibleHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Items []struct {
|
||||
ProductCode string `json:"productCode"`
|
||||
ProductName string `json:"productName"`
|
||||
ProducibleQty int `json:"producibleQty"`
|
||||
ShortText string `json:"shortText"` // 短板物料描述,如 "SCR-M4-12缺20; XX缺5"
|
||||
ComputedAt int64 `json:"computedAt"`
|
||||
} `json:"items"`
|
||||
Demands []struct {
|
||||
MaterialCode string `json:"materialCode"`
|
||||
Future5Qty int `json:"future5Qty"`
|
||||
} `json:"demands"`
|
||||
}
|
||||
if err := parseJSON(r, &req); err != nil {
|
||||
fail(w, http.StatusBadRequest, "参数错误: "+err.Error())
|
||||
if ctx.Mes == nil {
|
||||
fail(w, http.StatusBadRequest, "未配置 MES 地址,无法获取可生产数量")
|
||||
return
|
||||
}
|
||||
res, err := ctx.Mes.FetchProducible(ctx0())
|
||||
if err != nil {
|
||||
fail(w, http.StatusBadGateway, "拉取 MES 可生产数量失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
|
||||
tx, err := ctx.EntClient.Tx(ctx0())
|
||||
if err != nil {
|
||||
fail(w, http.StatusInternalServerError, "开启事务失败: "+err.Error())
|
||||
@@ -48,12 +40,11 @@ func producibleSyncHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
}
|
||||
}()
|
||||
|
||||
// 可生产快照:全量覆盖
|
||||
if _, err = tx.ProducibleSnapshot.Delete().Exec(ctx0()); err != nil {
|
||||
fail(w, http.StatusInternalServerError, "清理旧快照失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
for _, it := range req.Items {
|
||||
for _, it := range res.Items {
|
||||
if it.ProductCode == "" {
|
||||
continue
|
||||
}
|
||||
@@ -70,24 +61,21 @@ func producibleSyncHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// 未来5天需求:全量覆盖(demands 缺省时不动,允许只推快照不推需求)
|
||||
if req.Demands != nil {
|
||||
if _, err = tx.MaterialDemand.Delete().Exec(ctx0()); err != nil {
|
||||
fail(w, http.StatusInternalServerError, "清理旧需求失败: "+err.Error())
|
||||
return
|
||||
if _, err = tx.MaterialDemand.Delete().Exec(ctx0()); err != nil {
|
||||
fail(w, http.StatusInternalServerError, "清理旧需求失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
for _, d := range res.Demands {
|
||||
if d.MaterialCode == "" {
|
||||
continue
|
||||
}
|
||||
for _, d := range req.Demands {
|
||||
if d.MaterialCode == "" {
|
||||
continue
|
||||
}
|
||||
if _, err = tx.MaterialDemand.Create().
|
||||
SetMaterialCode(d.MaterialCode).
|
||||
SetFuture5Qty(d.Future5Qty).
|
||||
SetUpdatedAt(now).
|
||||
Save(ctx0()); err != nil {
|
||||
fail(w, http.StatusInternalServerError, "写入需求失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
if _, err = tx.MaterialDemand.Create().
|
||||
SetMaterialCode(d.MaterialCode).
|
||||
SetFuture5Qty(d.Future5Qty).
|
||||
SetUpdatedAt(now).
|
||||
Save(ctx0()); err != nil {
|
||||
fail(w, http.StatusInternalServerError, "写入需求失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,25 +84,12 @@ func producibleSyncHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
committed = true
|
||||
ok(w, map[string]any{"items": len(req.Items), "demands": len(req.Demands)})
|
||||
}
|
||||
}
|
||||
|
||||
// queryProducibleHandler 可生产数量快照查询(WMS 库存页卡片数据源)
|
||||
// 返回 MES 最近推送的快照列表 + 同步时间;从未推送过则返回空列表,前端提示"暂无数据(等待 MES 同步)"。
|
||||
func queryProducibleHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
list, err := ctx.EntClient.ProducibleSnapshot.Query().All(ctx0())
|
||||
if err != nil {
|
||||
fail(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
syncedAt := int64(0)
|
||||
for _, s := range list {
|
||||
if s.SyncedAt > syncedAt {
|
||||
syncedAt = s.SyncedAt
|
||||
}
|
||||
}
|
||||
ok(w, map[string]any{"list": list, "syncedAt": syncedAt})
|
||||
ok(w, map[string]any{"list": list, "syncedAt": now})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user