Files
bj_power/bj_power_workstation/internal/handler/workpiece.go
T
SunYF 1cc93795ce feat(mes): 添加定时同步可生产数量到WMS及BOM项相关标准字段
- 在main.go中添加定时任务每10分钟同步可生产数量到WMS系统
- 为BomItem实体添加relatedStandard字段及相关CRUD方法
- 为InspectionRecord实体添加reportNo、materialCode、materialName等字段
- 更新ent schema确保新字段的验证和默认值设置
- 添加必要的数据库迁移和字段映射逻辑
2026-09-17 12:49:07 +08:00

181 lines
6.0 KiB
Go
Raw 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"
"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})
}
}