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

162 lines
4.4 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 mesclient MES 内部接口客户端(备料单拉取/状态回写,AGV 配送用)。
package mesclient
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
)
// Client MES 内部接口客户端
type Client struct {
baseURL string
token string
hc *http.Client
}
func New(baseURL, token string) *Client {
if baseURL == "" {
baseURL = "http://127.0.0.1:8888"
}
return &Client{
baseURL: baseURL,
token: token,
hc: &http.Client{Timeout: 6 * time.Second},
}
}
// MaterialRequest MES 备料单行
type MaterialRequest struct {
ID int `json:"id"`
RequestNo string `json:"requestNo"`
OrderNo string `json:"orderNo"`
PlanDate string `json:"planDate"`
MaterialCode string `json:"materialCode"`
MaterialName string `json:"materialName"`
Unit string `json:"unit"`
ManageMode string `json:"manageMode"`
ReqQty float64 `json:"reqQty"`
Status string `json:"status"`
TargetDock string `json:"targetDock"`
Operator string `json:"operator"`
}
// ListMaterialRequests 拉取备料单(含 target_dock
// status 空=全部;传 PENDING 可只取待发料。
func (c *Client) ListMaterialRequests(ctx context.Context, status string) ([]MaterialRequest, error) {
u := c.baseURL + "/api/internal/material-requests"
q := ""
if status != "" {
q = "?status=" + status
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u+q, nil)
if err != nil {
return nil, err
}
req.Header.Set("X-API-TOKEN", c.token)
resp, err := c.hc.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var env struct {
Code int `json:"code"`
Data []MaterialRequest `json:"data"`
Msg string `json:"message"`
}
dec := json.NewDecoder(resp.Body)
// MES 的 data 可能是 [object] 数组
if err := dec.Decode(&env); err != nil {
return nil, err
}
if env.Data == nil {
return []MaterialRequest{}, nil
}
return env.Data, nil
}
// ProducibleItem MES 实时计算的可生产数量行
type ProducibleItem struct {
ProductCode string `json:"productCode"`
ProductName string `json:"productName"`
ProducibleQty int `json:"producibleQty"`
ShortText string `json:"shortText"`
ComputedAt int64 `json:"computedAt"`
}
// ProducibleDemand MES 实时计算的未来5天物料需求行
type ProducibleDemand struct {
MaterialCode string `json:"materialCode"`
Future5Qty int `json:"future5Qty"`
}
// ProducibleResult MES /api/internal/producible 返回体
type ProducibleResult struct {
Items []ProducibleItem `json:"items"`
Demands []ProducibleDemand `json:"demands"`
ComputedAt int64 `json:"computedAt"`
}
// FetchProducible 实时向 MES 拉取「可生产数量 + 未来5天物料需求」。
// 两系统之间不做定时/批量同步:WMS 打开页面时按需拉一次,MES 现算现返。
func (c *Client) FetchProducible(ctx context.Context) (*ProducibleResult, error) {
u := c.baseURL + "/api/internal/producible"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
return nil, err
}
req.Header.Set("X-API-TOKEN", c.token)
resp, err := c.hc.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var env struct {
Code int `json:"code"`
Data ProducibleResult `json:"data"`
Msg string `json:"message"`
}
if err := json.NewDecoder(resp.Body).Decode(&env); err != nil {
return nil, err
}
if env.Code != 0 {
msg := env.Msg
if msg == "" {
msg = "MES 返回失败"
}
return nil, errors.New(msg)
}
return &env.Data, nil
}
// MarkStatus 回写备料单状态(DELIVERING / DONE
func (c *Client) MarkStatus(ctx context.Context, requestNo, status string) error {
b, _ := json.Marshal(map[string]string{"requestNo": requestNo, "status": status})
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/api/internal/material-request/status", bytes.NewReader(b))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-TOKEN", c.token)
resp, err := c.hc.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
return &RespError{Status: resp.StatusCode}
}
return nil
}
type RespError struct {
Status int
}
func (e *RespError) Error() string {
return "mes call failed with status " + fmt.Sprintf("%d", e.Status)
}