Files
bj_power/bj_power_wms/internal/mesclient/client.go
T
SunYF 0e769f3813 feat(production): 新增排产支撑功能并移除手动报工页面
- 在main.go中更新排产物料需求注释说明,明确WMS与MES系统间交互方式
- 从前端help.js中移除手动报工(helpScan)相关帮助文档
- 更新工艺流程、绩效报表等页面帮助文档中的报工流程说明
- 在主布局中添加排产支撑菜单项并移除手动报工菜单项
- 新增ProducibleSupport.vue组件实现排产支撑页面功能
- 移除Scan.vue手动报工页面组件
- 更新相关帮助文档内容以匹配新的业务流程
2026-09-21 14:06:05 +08:00

207 lines
5.8 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 mesclient MES 内部接口客户端(备料单拉取/状态回写,AGV 配送用)。
package mesclient
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
"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
}
// MaterialDemandRow MES 排产物料需求行(按物料汇总,未来 N 天)
// WMS「缺料补货」视图拉此数据,对比本地可用库存得出排产缺料量。
type MaterialDemandRow struct {
MaterialCode string `json:"materialCode"`
MaterialName string `json:"materialName"`
Unit string `json:"unit"`
DemandQty int `json:"demandQty"` // 未来 N 天排产总需求(台数×单台用量,向上取整)
StartDate string `json:"startDate"` // 需求窗口起(YYYY-MM-DD)
EndDate string `json:"endDate"` // 需求窗口止(YYYY-MM-DD)
}
// FetchMaterialDemand 实时向 MES 拉取「排产物料需求量」(供 WMS 缺料补货视图)。
// 两系统之间不做定时/批量同步:WMS 打开页面时按需拉一次,MES 现算现返。
// days 不传默认 5(与历史未来5天口径一致);MES 内部 /api/internal/material-demand 支持 ?days 覆盖。
func (c *Client) FetchMaterialDemand(ctx context.Context, days int) ([]MaterialDemandRow, error) {
u := c.baseURL + "/api/internal/material-demand"
if days > 0 {
u += "?days=" + strconv.Itoa(days)
}
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 []MaterialDemandRow `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)
}
if env.Data == nil {
return []MaterialDemandRow{}, nil
}
return env.Data, nil
}
// DockRow MES 接驳台主数据行(dock 真源已迁 MES,WMS 仅只读取用)。
type DockRow struct {
ID int64 `json:"id"`
DockCode string `json:"dockCode"`
Name string `json:"name"`
DockType string `json:"dockType"`
StationNo int `json:"stationNo"`
Status string `json:"status"`
HasPallet bool `json:"hasPallet"`
PalletRef string `json:"palletRef"`
}
// ListDocks 拉取 MES 接驳台主数据(dock 真源在 MES)。
// WMS 出库目标工位下拉 / AGV 页接驳台列表均读此接口,仓库不再本地维护 dock 表。
func (c *Client) ListDocks(ctx context.Context) ([]DockRow, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.baseURL+"/api/internal/docks", 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 struct {
List []DockRow `json:"list"`
} `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)
}
if env.Data.List == nil {
return []DockRow{}, nil
}
return env.Data.List, 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)
}