181 lines
6.0 KiB
Go
181 lines
6.0 KiB
Go
package handler
|
||||
|
|
|
|||
|
|
import (
|
|||
|
|
"encoding/json"
|
|||
|
|
"io"
|
|||
|
|
"net/http"
|
|||
|
|
"net/url"
|
|||
|
|
"strings"
|
|||
|
|
|
|||
|
|
"bj_power_workstation/internal/svc"
|
|||
|
|
|
|||
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// passJSON 原样透传 MES 的 {code,message,data} 响应体(不再二次包装)。
|
|||
|
|
func passJSON(w http.ResponseWriter, body []byte) {
|
|||
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|||
|
|
w.WriteHeader(http.StatusOK)
|
|||
|
|
_, _ = w.Write(body)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// wipHandler GET /api/wip?stationNo= —— 代理 MES /api/internal/workpieces/in-process。
|
|||
|
|
// 在制品默认展示(5.2):停在本工位/上线位(0)/下线位(13) 的未完工工件列表。
|
|||
|
|
func wipHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
|||
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
params := url.Values{}
|
|||
|
|
if sn := strings.TrimSpace(r.URL.Query().Get("stationNo")); sn != "" {
|
|||
|
|
params.Set("stationNo", sn)
|
|||
|
|
}
|
|||
|
|
body, _, err := ctx.Mes.Get("/api/internal/workpieces/in-process", params)
|
|||
|
|
if err != nil {
|
|||
|
|
fail(w, http.StatusBadGateway, "MES 服务不可达:"+errString(err))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
passJSON(w, body)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// bomHandler GET /api/bom?productCode=&bomName= —— 代理 MES /api/internal/bom。
|
|||
|
|
// 上线建档「领料确认」按物料清单展示应领料。
|
|||
|
|
func bomHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
|||
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
params := url.Values{}
|
|||
|
|
if v := strings.TrimSpace(r.URL.Query().Get("productCode")); v != "" {
|
|||
|
|
params.Set("productCode", v)
|
|||
|
|
}
|
|||
|
|
if v := strings.TrimSpace(r.URL.Query().Get("bomName")); v != "" {
|
|||
|
|
params.Set("bomName", v)
|
|||
|
|
}
|
|||
|
|
body, _, err := ctx.Mes.Get("/api/internal/bom", params)
|
|||
|
|
if err != nil {
|
|||
|
|
fail(w, http.StatusBadGateway, "MES 服务不可达:"+errString(err))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
passJSON(w, body)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// orderQueryHandler GET /api/order/query?orderNo= —— 代理 MES /api/internal/order/query。
|
|||
|
|
// 上线建档选工单后带出产品编码/名称(用于查 BOM 应领料)。
|
|||
|
|
func orderQueryHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
|||
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
params := url.Values{}
|
|||
|
|
if v := strings.TrimSpace(r.URL.Query().Get("orderNo")); v != "" {
|
|||
|
|
params.Set("orderNo", v)
|
|||
|
|
}
|
|||
|
|
body, _, err := ctx.Mes.Get("/api/internal/order/query", params)
|
|||
|
|
if err != nil {
|
|||
|
|
fail(w, http.StatusBadGateway, "MES 服务不可达:"+errString(err))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
passJSON(w, body)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// traceHandler GET /api/trace?sn= —— 代理 MES /api/internal/workpiece/trace。
|
|||
|
|
// 下线完工面板扫 SN 后展示工件状态/工序时间线/拧紧等追溯信息。
|
|||
|
|
func traceHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
|||
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
sn := strings.TrimSpace(r.URL.Query().Get("sn"))
|
|||
|
|
if sn == "" {
|
|||
|
|
fail(w, http.StatusBadRequest, "缺少 sn 参数")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
body, _, err := ctx.Mes.Get("/api/internal/workpiece/trace", url.Values{"sn": {sn}})
|
|||
|
|
if err != nil {
|
|||
|
|
fail(w, http.StatusBadGateway, "MES 服务不可达:"+errString(err))
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
passJSON(w, body)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// onlineHandler POST /api/workpiece/online —— 上线建档(StationNo=0)。
|
|||
|
|
// {sn, orderNo, workOrderId, processSeq, operator};MES 不可达时写离线队列(kind=online_register)稍后重传。
|
|||
|
|
func onlineHandler(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 struct {
|
|||
|
|
Sn string `json:"sn"`
|
|||
|
|
OrderNo string `json:"orderNo"`
|
|||
|
|
Operator string `json:"operator"`
|
|||
|
|
}
|
|||
|
|
_ = json.Unmarshal(payload, &req)
|
|||
|
|
if strings.TrimSpace(req.Sn) == "" {
|
|||
|
|
fail(w, http.StatusBadRequest, "缺少 sn")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
ctx.Syncer.RunOnce(r.Context())
|
|||
|
|
ctx.Store.AddEventLog(req.OrderNo, req.Operator, "online_register", "上线建档 sn="+req.Sn)
|
|||
|
|
|
|||
|
|
q := url.Values{}
|
|||
|
|
if req.Operator != "" {
|
|||
|
|
q.Set("operator", req.Operator)
|
|||
|
|
}
|
|||
|
|
respBody, _, err := ctx.Mes.Post("/api/internal/workpiece/online?"+q.Encode(), json.RawMessage(payload))
|
|||
|
|
if err != nil {
|
|||
|
|
if qerr := ctx.Store.InsertQueueItem("online_register", string(payload)); qerr != nil {
|
|||
|
|
fail(w, http.StatusInternalServerError, "上报失败且离线队列写入失败:"+qerr.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
logx.Errorf("上线建档失败已离线排队: %v", err)
|
|||
|
|
ok(w, map[string]any{"queued": true})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
if msg := mesRespCode(respBody); msg != "" {
|
|||
|
|
fail(w, http.StatusConflict, msg)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
ok(w, map[string]any{"queued": false})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// doneHandler POST /api/workpiece/done —— 下线完工入库(StationNo=13)。
|
|||
|
|
// {sn, batchItems, serialItems, operator};完工内部自动回流 WMS 成品库存;
|
|||
|
|
// MES 不可达时写离线队列(kind=offline_finish)稍后重传。
|
|||
|
|
func doneHandler(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 struct {
|
|||
|
|
Sn string `json:"sn"`
|
|||
|
|
Operator string `json:"operator"`
|
|||
|
|
}
|
|||
|
|
_ = json.Unmarshal(payload, &req)
|
|||
|
|
if strings.TrimSpace(req.Sn) == "" {
|
|||
|
|
fail(w, http.StatusBadRequest, "缺少 sn")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
ctx.Syncer.RunOnce(r.Context())
|
|||
|
|
ctx.Store.AddEventLog("", req.Operator, "offline_finish", "下线完工入库 sn="+req.Sn)
|
|||
|
|
|
|||
|
|
q := url.Values{}
|
|||
|
|
if req.Operator != "" {
|
|||
|
|
q.Set("operator", req.Operator)
|
|||
|
|
}
|
|||
|
|
respBody, _, err := ctx.Mes.Post("/api/internal/workpiece/done?"+q.Encode(), json.RawMessage(payload))
|
|||
|
|
if err != nil {
|
|||
|
|
if qerr := ctx.Store.InsertQueueItem("offline_finish", string(payload)); qerr != nil {
|
|||
|
|
fail(w, http.StatusInternalServerError, "上报失败且离线队列写入失败:"+qerr.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
logx.Errorf("下线完工上报失败已离线排队: %v", err)
|
|||
|
|
ok(w, map[string]any{"queued": true})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
if msg := mesRespCode(respBody); msg != "" {
|
|||
|
|
fail(w, http.StatusConflict, msg)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
ok(w, map[string]any{"queued": false})
|
|||
|
|
}
|
|||
|
|
}
|