Files
bj_power/bj_power_mes/internal/handler/station.go
T
SunYF ae4c292487 feat: 完成产线MES系统全流程功能迭代与优化
本提交完成了多个核心模块的功能完善与业务对齐:
1. 工位终端:固定工位配置、移除自选工位逻辑、适配配置化工位号
2. MES核心:重构工位组合逻辑、新增工单/流程状态管理、补全报工/追溯逻辑
3. WMS客户端:新增修改密码功能、优化帮助弹窗逻辑
4. 文档与权限:补充完整操作手册、统一菜单名称与权限描述
5. 修复多业务校验:排产数量校验、工单状态校验、工位绑定规则
2026-08-31 12:58:28 +08:00

168 lines
5.1 KiB
Go

package handler
import (
"net/http"
"strconv"
"bj_power_mes/common/httpx"
"bj_power_mes/internal/logic"
"bj_power_mes/internal/svc"
)
// atoiDefault 解析整型字符串,非法返回默认值
func atoiDefault(s string, def int) int {
if s == "" {
return def
}
if n, err := strconv.Atoi(s); err == nil {
return n
}
return def
}
// operator 从 JWT 上下文取操作人,取不到回退 fallback
func operator(r *http.Request, fallback string) string {
if v, ok := r.Context().Value("name").(string); ok && v != "" {
return v
}
if v, ok := r.Context().Value("username").(string); ok && v != "" {
return v
}
if fallback != "" {
return fallback
}
return "system"
}
// StationLoginInternalHandler 工位终端登录(内部接口,X-API-TOKEN 保护)
// 校验 用户名 + 工位终端密码 + 工位权限,签发与 MES 同密钥 JWT
func StationLoginInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req logic.StationLoginReq
if err := httpx.ParseJSON(r, &req); err != nil {
httpx.BadRequest(w, "请求体解析失败")
return
}
data, err := logic.New(svcCtx).StationLogin(r.Context(), req)
if err != nil {
httpx.Fail(w, 2101, err.Error())
return
}
httpx.Ok(w, data)
}
}
// StationChangePasswordInternalHandler 工位终端修改自己的工位终端密码
func StationChangePasswordInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req struct {
UserId int `json:"userId"`
OldPassword string `json:"oldPassword"`
NewPassword string `json:"newPassword"`
}
if err := httpx.ParseJSON(r, &req); err != nil {
httpx.BadRequest(w, "请求体解析失败")
return
}
if err := logic.New(svcCtx).StationChangePassword(r.Context(), req.UserId, req.OldPassword, req.NewPassword); err != nil {
httpx.Fail(w, 2102, err.Error())
return
}
httpx.OkMessage(w, "工位终端密码修改成功", nil)
}
}
// StationTaskInternalHandler 工位终端拉取当前任务(工位/流程/步骤/活跃工单)
func StationTaskInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
stationNo := atoiDefault(r.URL.Query().Get("stationNo"), 0)
if stationNo <= 0 {
httpx.BadRequest(w, "缺少 stationNo 参数")
return
}
data, err := logic.New(svcCtx).StationTask(r.Context(), stationNo)
if err != nil {
httpx.Fail(w, 2103, err.Error())
return
}
httpx.Ok(w, data)
}
}
// StationReportInternalHandler 工位终端工序报工(写工序实绩 + 步骤考核)
func StationReportInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req logic.ReportProcessReq
if err := httpx.ParseJSON(r, &req); err != nil {
httpx.BadRequest(w, "请求体解析失败")
return
}
if err := logic.New(svcCtx).ReportProcess(r.Context(), req, operator(r, "")); err != nil {
httpx.Fail(w, 2104, err.Error())
return
}
httpx.OkMessage(w, "报工成功", nil)
}
}
// WorkloadInternalHandler 工作量/绩效报表(工位终端"我的工作量" + MES 绩效报表共用)
// operator=操作人、stationNo=工位号(空=全部工位)、from/to=日期范围
func WorkloadInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
data, err := logic.New(svcCtx).Workload(r.Context(), q.Get("operator"), q.Get("stationNo"), q.Get("from"), q.Get("to"))
if err != nil {
httpx.Fail(w, 2105, err.Error())
return
}
httpx.Ok(w, data)
}
}
// FileDownloadInternalHandler 内部文件下载(工艺图纸 PDF,供工位终端代理)
func FileDownloadInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
serveUploadFile(w, r, svcCtx.Config.Upload.Dir, r.URL.Query().Get("name"))
}
}
// StationCheckinInternalHandler 工位终端暂存退库(半成品入库,块4/5)
// 记录已完成工序后按半成品 INBOUND 流转,并通知 WMS 入库。
func StationCheckinInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req struct {
Sn string `json:"sn"`
OrderNo string `json:"orderNo"`
StationNo int `json:"stationNo"`
ProcessCode int `json:"processCode"`
Operator string `json:"operator"`
}
if err := httpx.ParseJSON(r, &req); err != nil {
httpx.BadRequest(w, "请求体解析失败")
return
}
if req.Sn == "" {
httpx.BadRequest(w, "缺少 sn")
return
}
doneCodes := []int{}
if req.ProcessCode > 0 {
doneCodes = append(doneCodes, req.ProcessCode)
}
op := req.Operator
if op == "" {
op = operator(r, "")
}
if err := logic.New(svcCtx).SemiFlow(r.Context(), logic.SemiReq{
Sn: req.Sn,
OrderNo: req.OrderNo,
DoneProcessCodes: doneCodes,
Action: "INBOUND",
}, op); err != nil {
httpx.Fail(w, 2106, err.Error())
return
}
httpx.OkMessage(w, "暂存退库已登记", nil)
}
}