feat: 新增装机绑定功能与权限、BOM工序配置

1.  新增装机绑定实体与相关CRUD逻辑,支持工件工序物料绑定/解绑
2.  为BOM物料新增装配工序字段,支持按工序校验绑定
3.  扩展权限表,新增父权限码字段支持菜单按钮关联
4.  统一各页面帮助弹窗参数,新增角色管理帮助文档
5.  新增公共格式化工具函数,优化侧边栏菜单展开逻辑
6.  新增工位终端绑定代理接口与MES内部绑定API
7.  修复主入口数据库连接与schema初始化逻辑,新增一键迁移工具
This commit is contained in:
SunYF
2026-09-07 11:58:19 +08:00
parent 92f0439d89
commit 6ee131a4bd
70 changed files with 6966 additions and 365 deletions
@@ -0,0 +1,152 @@
package production
import (
"net/http"
"strconv"
"bj_power_mes/common/httpx"
"bj_power_mes/internal/logic"
"bj_power_mes/internal/svc"
)
func itoa(n int) string { return strconv.Itoa(n) }
// BindReq 绑定提交请求
type BindReq struct {
Sn string `json:"sn"`
OrderNo string `json:"orderNo"`
ProcessCode int `json:"processCode"`
StationNo int `json:"stationNo"`
Operator string `json:"operator"`
Items []logic.BindItemReq `json:"items"`
}
func doBind(svcCtx *svc.ServiceContext, r *http.Request) (any, error) {
var req BindReq
if err := httpx.ParseJSON(r, &req); err != nil {
return nil, err
}
if req.Sn == "" || req.ProcessCode <= 0 {
return nil, nil
}
op := operator(r, req.Operator)
stationNo := ""
if req.StationNo > 0 {
stationNo = itoa(req.StationNo)
}
return logic.New(svcCtx).BindWorkpiece(r.Context(), req.Sn, req.OrderNo, req.ProcessCode, stationNo, op, req.Items)
}
// BindHandler POST /api/v1/binds —— MES 手动报工页/巡检录绑
func BindHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
data, err := doBind(svcCtx, r)
if err != nil {
httpx.Fail(w, 3309, err.Error())
return
}
if data == nil {
httpx.BadRequest(w, "sn / processCode 必填")
return
}
httpx.Ok(w, data)
}
}
// BindInternalHandler POST /api/internal/workpiece/binds —— 工位终端扫码绑料
func BindInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
data, err := doBind(svcCtx, r)
if err != nil {
httpx.Fail(w, 2111, err.Error())
return
}
if data == nil {
httpx.BadRequest(w, "sn / processCode 必填")
return
}
httpx.Ok(w, data)
}
}
func doUnbind(svcCtx *svc.ServiceContext, r *http.Request) error {
var req struct {
Sn string `json:"sn"`
ProcessCode int `json:"processCode"`
MaterialCode string `json:"materialCode"`
BindValue string `json:"bindValue"`
Operator string `json:"operator"`
}
if err := httpx.ParseJSON(r, &req); err != nil {
return err
}
return logic.New(svcCtx).RemoveBind(r.Context(), req.Sn, req.ProcessCode, req.MaterialCode, req.BindValue, operator(r, req.Operator))
}
// UnbindHandler POST /api/v1/binds/remove —— 撤销误绑(未报工前)
func UnbindHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := doUnbind(svcCtx, r); err != nil {
httpx.Fail(w, 3310, err.Error())
return
}
httpx.OkMessage(w, "已撤销绑定", nil)
}
}
// UnbindInternalHandler POST /api/internal/workpiece/binds/remove
func UnbindInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := doUnbind(svcCtx, r); err != nil {
httpx.Fail(w, 2112, err.Error())
return
}
httpx.OkMessage(w, "已撤销绑定", nil)
}
}
// ---------- 装机绑定:应绑清单/齐套状态查询 ----------
// bindPanelFromReq 通用查询逻辑:按 sn+processCode 返回绑定面板(应绑物料+已绑情况)
func bindPanelFromReq(svcCtx *svc.ServiceContext, r *http.Request) (any, error) {
sn := r.URL.Query().Get("sn")
processCode := atoiDefault(r.URL.Query().Get("processCode"), 0)
if sn == "" || processCode <= 0 {
return nil, nil
}
return logic.New(svcCtx).StationBindPanelData(r.Context(), sn, processCode)
}
// BindPanelHandler GET /api/v1/bind-panel?sn=&processCode=
// 手动报工页在报工前拉取"本工件本工序应装什么料、已装什么",展示引导并做齐套校验。
func BindPanelHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
data, err := bindPanelFromReq(svcCtx, r)
if err != nil {
httpx.Fail(w, 3308, err.Error())
return
}
if data == nil {
httpx.BadRequest(w, "缺少 sn / processCode 参数")
return
}
httpx.Ok(w, data)
}
}
// BindPanelInternalHandler GET /api/internal/workpiece/bind-panel?sn=&processCode=
// 工位终端(12 个触控一体机)扫码工件后拉取绑定面板,驱动工人扫码绑料。
func BindPanelInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
data, err := bindPanelFromReq(svcCtx, r)
if err != nil {
httpx.Fail(w, 2110, err.Error())
return
}
if data == nil {
httpx.BadRequest(w, "缺少 sn / processCode 参数")
return
}
httpx.Ok(w, data)
}
}