初始化

This commit is contained in:
SunYF
2026-08-28 14:07:22 +08:00
parent a185247ab1
commit b34325a16f
971 changed files with 291 additions and 220360 deletions
@@ -1,103 +0,0 @@
package handler
import (
"net/http"
"net/url"
"strconv"
"strings"
"bj_power_workstation/internal/mes"
)
// taskCurrentHandler 代理 MES GET /api/internal/station/task?dockCode=。
// 响应体原样透传(MES 已按 {code,message,data} 封装,这里不再二次包装,避免双重嵌套);
// MES 不可达时返回 502 JSON 错误。
func taskCurrentHandler(mesc *mes.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
dockCode := strings.TrimSpace(r.URL.Query().Get("dockCode"))
if dockCode == "" {
fail(w, http.StatusBadRequest, "缺少 dockCode 参数")
return
}
body, _, err := mesc.Get("/api/internal/station/task", url.Values{"dockCode": {dockCode}})
if err != nil {
fail(w, http.StatusBadGateway, "MES 服务不可达:"+errString(err))
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = w.Write(body)
}
}
// ---------- 工艺 PDF 直通代理 ----------
//
// 二选一说明:本工程采用「本地无鉴权前缀 /pdfopen/<name>」方案——iframe/img/window.open
// 无法方便地携带 Authorization 头,因此对 /pdfopen/ 路径免 JWT 并解析路径参数作为文件名,
// 内部仍走 MES /api/internal/files/<name>(内部 API 由 X-API-TOKEN 保护)。
// 同时保留需登录态的 GET /api/pdf?name=<file> 供程序化调用。
// 两端点均把文件流原样转发并透传 Content-Type/Content-Disposition,不套 {code,message,data}。
// pdfQueryHandler GET /api/pdf?name=<file>(需登录)
func pdfQueryHandler(mesc *mes.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
forwardFile(w, mesc, strings.TrimSpace(r.URL.Query().Get("name")))
}
}
// pdfOpenHandler GET /pdfopen/<name>(免鉴权,供 iframe 直链)
func pdfOpenHandler(mesc *mes.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// go-zero 路由参数也可用 PathVar,此处直接解析 URL 以减少对外部 API 的依赖
raw := strings.TrimPrefix(r.URL.EscapedPath(), "/pdfopen/")
name, err := url.PathUnescape(raw)
if err != nil {
fail(w, http.StatusBadRequest, "非法文件名")
return
}
forwardFile(w, mesc, name)
}
}
// forwardFile 校验单段文件名后拉取 MES 文件流并原样转发。
func forwardFile(w http.ResponseWriter, mesc *mes.Client, name string) {
name = strings.TrimSpace(name)
if name == "" {
fail(w, http.StatusBadRequest, "缺少文件名")
return
}
if strings.ContainsAny(name, `/\`) || name == "." || name == ".." || strings.Contains(name, "..") {
fail(w, http.StatusBadRequest, "非法文件名")
return
}
body, header, err := mesc.Get("/api/internal/files/"+url.PathEscape(name), nil)
if err != nil {
fail(w, http.StatusBadGateway, "工艺文件获取失败:"+errString(err))
return
}
ct := header.Get("Content-Type")
if ct == "" {
ct = "application/pdf"
}
w.Header().Set("Content-Type", ct)
if cd := header.Get("Content-Disposition"); cd != "" {
w.Header().Set("Content-Disposition", cd)
}
w.Header().Set("X-Original-Filename", strconv.Quote(name))
w.WriteHeader(http.StatusOK)
_, _ = w.Write(body)
}
// errString 压缩错误信息长度便于前端展示。
func errString(err error) string {
s := strings.TrimSpace(err.Error())
s = strings.ReplaceAll(s, "\n", " ")
const maxLen = 180
if len(s) > maxLen {
return s[:maxLen] + "..."
}
return s
}