feat: 五项目业务实现并对接完成
- MES(B): 工单/BOM/备料/工序字典/PLC下发/拧紧/扫码报工/半成品/AGV/追溯逻辑,WMS与海康RCS客户端,看板Redis缓存API(概览/设备/进度/报警/趋势)+SSE - WMS(C): JWT滑动续签、Excel导入、盘点、内部API、种子数据、独立Postgres配置 - WMS客户端(E): Go网关8891反向代理+内嵌Vue3十页 - 工位终端(D): SQLite本地缓存+模拟拧紧源+内嵌Vue3页面 - Dashboard(A): 看板数据改接MES内部缓存API,SSE实时刷新+vite代理 - 清理各项目球形磨遗留代码,新增部署手册.md
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
package wmsstock
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Client WMS 内部 API 客户端(X-API-TOKEN 写死 token 保护)
|
||||
type Client struct {
|
||||
BaseURL string
|
||||
Token string
|
||||
HTTP *http.Client
|
||||
}
|
||||
|
||||
func New(baseURL, token string) *Client {
|
||||
return &Client{
|
||||
BaseURL: baseURL,
|
||||
Token: token,
|
||||
HTTP: &http.Client{Timeout: 15 * time.Second},
|
||||
}
|
||||
}
|
||||
|
||||
// wmsResp WMS 统一响应 {code,message,data}
|
||||
type wmsResp struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Client) call(method, path string, body any) (json.RawMessage, error) {
|
||||
var rd io.Reader
|
||||
if body != nil {
|
||||
b, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rd = bytes.NewReader(b)
|
||||
}
|
||||
req, err := http.NewRequest(method, c.BaseURL+path, rd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("X-API-TOKEN", c.Token)
|
||||
resp, err := c.HTTP.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("WMS 不可达(%s): %w", path, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
raw, _ := io.ReadAll(resp.Body)
|
||||
var wr wmsResp
|
||||
if err := json.Unmarshal(raw, &wr); err != nil {
|
||||
return nil, fmt.Errorf("WMS 响应解析失败(%s): %s", path, truncate(string(raw), 200))
|
||||
}
|
||||
if wr.Code != 0 {
|
||||
return nil, fmt.Errorf("WMS 返回错误(%s): %s", path, wr.Message)
|
||||
}
|
||||
return wr.Data, nil
|
||||
}
|
||||
|
||||
func truncate(s string, n int) string {
|
||||
if len(s) > n {
|
||||
return s[:n]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ============ 数据结构(与 C 的内部接口契约对齐)============
|
||||
|
||||
type CheckItem struct {
|
||||
MaterialCode string `json:"materialCode"`
|
||||
Qty int `json:"qty"`
|
||||
}
|
||||
|
||||
type LockItem struct {
|
||||
MaterialCode string `json:"materialCode"`
|
||||
BatchNo string `json:"batchNo,omitempty"`
|
||||
Sn string `json:"sn,omitempty"`
|
||||
Qty int `json:"qty"`
|
||||
}
|
||||
|
||||
type LedgerItem struct {
|
||||
MaterialCode string `json:"materialCode"`
|
||||
MaterialName string `json:"materialName"`
|
||||
TotalQty int `json:"totalQty"`
|
||||
}
|
||||
|
||||
// ============ 业务方法 ============
|
||||
|
||||
// CheckStock 批量校验库存是否充足
|
||||
func (c *Client) CheckStock(items []CheckItem) (json.RawMessage, error) {
|
||||
return c.call(http.MethodPost, "/api/internal/stock/check", map[string]any{"items": items})
|
||||
}
|
||||
|
||||
// LockStock 锁定库存(结构件锁批次量 / 精密件逐 SN)
|
||||
func (c *Client) LockStock(orderNo string, items []LockItem) (json.RawMessage, error) {
|
||||
return c.call(http.MethodPost, "/api/internal/stock/lock", map[string]any{"orderNo": orderNo, "items": items})
|
||||
}
|
||||
|
||||
// UnlockStock 解锁库存
|
||||
func (c *Client) UnlockStock(orderNo string, lockIds []int) (json.RawMessage, error) {
|
||||
return c.call(http.MethodPost, "/api/internal/stock/unlock", map[string]any{"orderNo": orderNo, "lockIds": lockIds})
|
||||
}
|
||||
|
||||
// Deduct 出库扣减(领料出库,累计≤台账需求)
|
||||
func (c *Client) Deduct(req map[string]any) (json.RawMessage, error) {
|
||||
return c.call(http.MethodPost, "/api/internal/stock/deduct", req)
|
||||
}
|
||||
|
||||
// QueryStock 库存查询(FIFO 分配用)
|
||||
func (c *Client) QueryStock(materialCode, zoneCode string) (json.RawMessage, error) {
|
||||
return c.call(http.MethodGet, "/api/internal/stock/query?materialCode="+materialCode+"&zoneCode="+zoneCode+"&pageSize=500", nil)
|
||||
}
|
||||
|
||||
// LedgerSync 同步工单 BOM 台账到 WMS
|
||||
func (c *Client) LedgerSync(orderNo, productCode string, items []LedgerItem) (json.RawMessage, error) {
|
||||
return c.call(http.MethodPost, "/api/internal/ledger/sync", map[string]any{
|
||||
"orderNo": orderNo, "productCode": productCode, "items": items,
|
||||
})
|
||||
}
|
||||
|
||||
// SemiInbound 半成品入库暂存
|
||||
func (c *Client) SemiInbound(sn, materialCode, completedProcess, zoneCode, orderNo, operator string) (json.RawMessage, error) {
|
||||
return c.call(http.MethodPost, "/api/internal/semi/inbound", map[string]any{
|
||||
"sn": sn, "materialCode": materialCode, "completedProcess": completedProcess,
|
||||
"zoneCode": zoneCode, "orderNo": orderNo, "operator": operator,
|
||||
})
|
||||
}
|
||||
|
||||
// SemiOutbound 半成品出库重上线
|
||||
func (c *Client) SemiOutbound(sn, zoneCode, operator string) (json.RawMessage, error) {
|
||||
return c.call(http.MethodPost, "/api/internal/semi/outbound", map[string]any{
|
||||
"sn": sn, "zoneCode": zoneCode, "operator": operator,
|
||||
})
|
||||
}
|
||||
|
||||
// DisplayOverview 库存总览(大屏用)
|
||||
func (c *Client) DisplayOverview() (json.RawMessage, error) {
|
||||
return c.call(http.MethodGet, "/api/internal/display/overview", nil)
|
||||
}
|
||||
Reference in New Issue
Block a user