Files
SunYF 37f10d3a13 refactor: 重构产线工位与备料流程,移除冗余字段
1. 移除工单、工件、日排产中的冗余工位组合/接驳台字段
2. 新增工位接驳台编码字段与唯一约束,关联WMS接驳台主数据
3. 重构日排产为工位产量分配模式,替代原接驳台列表
4. 新增备料单工位级字段与分批出库支持
5. 移除定时同步可生产数量,改为WMS实时拉取接口
6. 过滤操作日志,排除登录/退出相关日志
7. 调整仪表盘工序展示逻辑为今日派工路线
8. 新增接驳台维护菜单与基础数据
2026-09-19 07:50:21 +08:00

202 lines
6.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handler
import (
"encoding/json"
"io"
"net/http"
"net/url"
"strings"
"bj_power_workstation/internal/svc"
)
// ============ 产线点位 / 上位机移料 / 叫料(代理 MES 内部 API ============
// MES 侧对应接口均以 X-API-TOKEN 保护(/api/internal/line/*),本服务用配置 token 转发,
// 前端只与本服务交互(JWT 登录)。MES 响应体原样透传({code,message,data})。
// mesJSON 透传 MES 响应体;网络不可达时返回 502 中文提示。
func mesJSON(w http.ResponseWriter, body []byte, err error) bool {
if err != nil {
fail(w, http.StatusBadGateway, "MES 服务不可达:"+errString(err))
return false
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = w.Write(body)
return true
}
// linePointsHandler GET /api/line/points(产线点位台账:当前每个点位上的工件)
func linePointsHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
body, _, err := ctx.Mes.Get("/api/internal/line/points", nil)
mesJSON(w, body, err)
}
}
// lineMovesHandler GET /api/line/moves?status=&sn=&limit=(移料指令列表)
func lineMovesHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
q := url.Values{}
for _, k := range []string{"status", "sn", "limit"} {
if v := strings.TrimSpace(r.URL.Query().Get(k)); v != "" {
q.Set(k, v)
}
}
body, _, err := ctx.Mes.Get("/api/internal/line/moves", q)
mesJSON(w, body, err)
}
}
// lineMoveHandler POST /api/line/move(下发移料指令:起点位 → 目标点位)
// 请求体原样转发:{sn, fromPoint, toPoint, orderNo}
func lineMoveHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
payload, err := io.ReadAll(r.Body)
if err != nil {
fail(w, http.StatusBadRequest, "请求体读取失败")
return
}
var probe struct {
Sn string `json:"sn"`
FromPoint string `json:"fromPoint"`
ToPoint string `json:"toPoint"`
}
_ = json.Unmarshal(payload, &probe)
if probe.Sn == "" || probe.FromPoint == "" || probe.ToPoint == "" {
fail(w, http.StatusBadRequest, "工件SN、起点位、目标点位必填")
return
}
body, _, err := ctx.Mes.Post("/api/internal/line/move", json.RawMessage(payload))
mesJSON(w, body, err)
}
}
// lineArriveHandler POST /api/line/move/arrive(工件到位:回写台账并闭环指令)
func lineArriveHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
payload, err := io.ReadAll(r.Body)
if err != nil {
fail(w, http.StatusBadRequest, "请求体读取失败")
return
}
var probe struct {
CmdNo string `json:"cmdNo"`
}
_ = json.Unmarshal(payload, &probe)
if probe.CmdNo == "" {
fail(w, http.StatusBadRequest, "缺少指令号 cmdNo")
return
}
body, _, err := ctx.Mes.Post("/api/internal/line/move/arrive", json.RawMessage(payload))
mesJSON(w, body, err)
}
}
// lineAckHandler POST /api/line/move/ackPLC 应答:通常由 PLC 侧调用,终端手动应答也走这里)
func lineAckHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
payload, err := io.ReadAll(r.Body)
if err != nil {
fail(w, http.StatusBadRequest, "请求体读取失败")
return
}
body, _, err := ctx.Mes.Post("/api/internal/line/move/ack", json.RawMessage(payload))
mesJSON(w, body, err)
}
}
// lineOccupyHandler POST /api/line/occupy(点位人工记账:IN 上料 / OUT 下料)
// 请求体:{pointNo, sn, orderNo, action} —— operator 由本服务补当前登录人。
func lineOccupyHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
payload, err := io.ReadAll(r.Body)
if err != nil {
fail(w, http.StatusBadRequest, "请求体读取失败")
return
}
var req map[string]any
if err := json.Unmarshal(payload, &req); err != nil {
fail(w, http.StatusBadRequest, "请求体解析失败")
return
}
if req["operator"] == nil || req["operator"] == "" {
if u := currentUsername(r); u != "" {
req["operator"] = u
}
}
body, _ := json.Marshal(req)
resp, _, err := ctx.Mes.Post("/api/internal/line/occupy", json.RawMessage(body))
mesJSON(w, resp, err)
}
}
// lineCallMaterialHandler POST /api/line/call-material(工位终端叫料:选本工位接驳台)
// 请求体原样转发:{stationNo, dock, orderNo, items:[{materialCode, materialName, unit, manageMode, qty}]}
func lineCallMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
payload, err := io.ReadAll(r.Body)
if err != nil {
fail(w, http.StatusBadRequest, "请求体读取失败")
return
}
var req map[string]any
if err := json.Unmarshal(payload, &req); err != nil {
fail(w, http.StatusBadRequest, "请求体解析失败")
return
}
if req["operator"] == nil || req["operator"] == "" {
if u := currentUsername(r); u != "" {
req["operator"] = u
}
}
body, _ := json.Marshal(req)
resp, _, err := ctx.Mes.Post("/api/internal/line/call-material", json.RawMessage(body))
mesJSON(w, resp, err)
}
}
// materialRequestsHandler GET /api/material-requests 代理 MES /api/internal/material-requests
// 工位终端按当前登录工位过滤「待接料」行(stationNo 由前端带入)。
func materialRequestsHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
q := url.Values{}
for _, k := range []string{"stationNo", "status", "orderNo", "planDate", "materialCode", "targetDock"} {
if v := strings.TrimSpace(r.URL.Query().Get(k)); v != "" {
q.Set(k, v)
}
}
body, _, err := ctx.Mes.Get("/api/internal/material-requests", q)
mesJSON(w, body, err)
}
}
// materialReceiveHandler POST /api/material-request/receive 代理 MES /api/internal/station/receive-material
// 主入口:工人扫码接料(扫描备料单号确认)。operator 由本服务补当前登录人。
func materialReceiveHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
payload, err := io.ReadAll(r.Body)
if err != nil {
fail(w, http.StatusBadRequest, "请求体读取失败")
return
}
var req map[string]any
if err := json.Unmarshal(payload, &req); err != nil {
fail(w, http.StatusBadRequest, "请求体解析失败")
return
}
if req["requestNo"] == nil || req["requestNo"] == "" {
fail(w, http.StatusBadRequest, "缺少备料单号")
return
}
if req["operator"] == nil || req["operator"] == "" {
if u := currentUsername(r); u != "" {
req["operator"] = u
}
}
body, _ := json.Marshal(req)
resp, _, err := ctx.Mes.Post("/api/internal/station/receive-material", json.RawMessage(body))
mesJSON(w, resp, err)
}
}