Files
bj_power/bj_power_mes/main.go
T
SunYF 0ab21b1234 feat&refactor: 完成多模块功能迭代与配置优化
本次提交覆盖多个业务模块的功能完善与体验优化:
1.  **鉴权与配置调整**:
    - 统一JWT滑动续签逻辑,简化Token存储,移除RefreshToken相关冗余代码
    - 调整多项目配置文件中JWT过期时间为3600秒,统一会话闲置窗口
    - 工位配置放开1~12限制,改为仅校验大于0
2.  **术语统一替换**:全链路将"精密件"替换为"电气件",修正物料管理描述
3.  **功能新增**:
    - 新增工位类型、工艺路线与产线点位台账模块
    - 添加工艺PDF预览面板、工位终端代理转发接口
    - 新增操作日志按操作人列表筛选、工位登出日志记录
    - 新增PLC移料指令与产线点位状态管理
4.  **业务流程优化**:
    - 调整BOM物料删除校验逻辑,优化工单备料计算
    - 补充物料图号、检测单号等追溯字段
    - 完善工艺流程图与工位绑定关系说明
    - 优化前端页面文案与交互细节
5.  **代码规范与维护**:
    - 新增通用工具函数与前端静态资源
    - 整理路由权限与中间件逻辑
    - 修复部分接口与配置的不兼容问题
2026-09-10 16:59:15 +08:00

196 lines
5.7 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 main
import (
"bufio"
"context"
"crypto/subtle"
"embed"
"flag"
"fmt"
"io/fs"
"net/http"
"os"
"os/exec"
"runtime"
"strings"
"time"
"bj_power_mes/common/httpx"
xlog "bj_power_mes/common/logx"
"bj_power_mes/internal/config"
"bj_power_mes/internal/db"
"bj_power_mes/internal/handler"
"bj_power_mes/internal/logic"
"bj_power_mes/internal/svc"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest"
)
var configFile = flag.String("f", "etc/bj_power_mes-api.yaml", "the config file")
//go:embed public
var public embed.FS
// openBrowser 调用系统默认浏览器打开 url
func openBrowser(url string) {
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", url)
case "darwin":
cmd = exec.Command("open", url)
default:
cmd = exec.Command("xdg-open", url)
}
_ = cmd.Start()
}
// promptPassword 从终端读取一行输入(不隐藏回显,用于运维终端操作)
func promptPassword(msg string) string {
fmt.Print(msg)
line, _ := bufio.NewReader(os.Stdin).ReadString('\n')
return strings.TrimRight(line, "\r\n")
}
// adminGate 管理员密码门禁:敏感命令行操作必须输入与配置一致的密码才放行;
// 校验失败会记录日志并终止,绝不继续执行。
func adminGate(c config.Config) bool {
pwd := promptPassword("请输入管理员密码以执行 [" + flag.Arg(0) + "]: ")
if subtle.ConstantTimeCompare([]byte(pwd), []byte(c.Cli.AdminPassword)) != 1 {
logx.Errorf("敏感命令 [%s] 因管理员密码校验失败被终止", flag.Arg(0))
fmt.Println("管理员密码不正确,已终止该操作。")
return false
}
logx.Infof("敏感命令 [%s] 已通过管理员密码校验", flag.Arg(0))
return true
}
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
// 日志按天存储:logs/bj_power_mes-2026-01-02.log,保留 30 天
logger := xlog.NewLogger(c.Logger)
xlog.SetDefault(logger)
logx.SetWriter(logger)
logx.DisableStat()
defer func() { _ = logger.Close() }()
// 命令行子命令:DDL/数据操作一律显式触发 + 管理员密码门禁,不随服务启动自动改库
cmd := flag.Arg(0)
switch cmd {
case "migrate":
if !adminGate(c) {
os.Exit(1)
}
if err := db.EnsureDB(c.Database); err != nil {
logx.Errorf("ensure database failed: %v", err)
os.Exit(1)
}
if err := db.AutoMigrate(c.Database); err != nil {
logx.Errorf("migrate failed: %v", err)
os.Exit(1)
}
logx.Info("migrate 完成:数据库结构迁移成功(只增/补列,未删除任何数据)。")
fmt.Println("migrate: 数据库结构迁移成功(只增/补列,未删除任何数据)。")
return
case "reset-all":
fmt.Println("reset-all: 即将清空并重建全部表,此操作不可恢复!")
if !adminGate(c) {
os.Exit(1)
}
if err := db.EnsureDB(c.Database); err != nil {
logx.Errorf("ensure database failed: %v", err)
os.Exit(1)
}
if err := db.DropAllTables(c.Database); err != nil {
logx.Errorf("reset-all drop failed: %v", err)
os.Exit(1)
}
entClient, sqlDB := db.MustNewDB(c.Database)
defer entClient.Close()
defer sqlDB.Close()
if err := db.EnsureSchema(entClient, sqlDB); err != nil {
logx.Errorf("reset-all create failed: %v", err)
os.Exit(1)
}
if err := logic.New(&svc.ServiceContext{EntClient: entClient}).Seed(context.Background()); err != nil {
logx.Errorf("reset-all seed failed: %v", err)
os.Exit(1)
}
logx.Info("reset-all 完成:已清空并重建全部表,并写入基础数据。")
fmt.Println("reset-all: 已清空并重建全部表,并写入基础数据。")
return
case "seed":
if !adminGate(c) {
os.Exit(1)
}
if err := db.EnsureDB(c.Database); err != nil {
logx.Errorf("ensure database failed: %v", err)
os.Exit(1)
}
entClient, sqlDB := db.MustNewDB(c.Database)
defer entClient.Close()
defer sqlDB.Close()
if err := db.EnsureSchema(entClient, sqlDB); err != nil {
logx.Errorf("seed ensure schema failed: %v", err)
os.Exit(1)
}
if err := logic.New(&svc.ServiceContext{EntClient: entClient}).Seed(context.Background()); err != nil {
logx.Errorf("seed failed: %v", err)
os.Exit(1)
}
logx.Info("seed 完成:基础数据已对齐。")
fmt.Println("seed: 基础数据已对齐。")
return
case "", "serve":
// 正常启动服务
default:
fmt.Println("未知命令: " + cmd + ";可用命令: migrate / reset-all / seed / serve")
os.Exit(1)
}
svcCtx := svc.NewServiceContext(c)
// 启动时对齐基础数据(角色、admin 账号、菜单、工序模板、工位派工);本次不再自动建表
if err := logic.New(svcCtx).Seed(context.Background()); err != nil {
logx.Errorf("Seed failed: %v", err)
}
// 内嵌前端(public/SPA
sub, _ := fs.Sub(public, "public")
spaHandler := httpx.NewNotFoundHandler(http.FS(sub))
server := rest.MustNewServer(
c.RestConf,
rest.WithCors("*"),
rest.WithNotFoundHandler(http.HandlerFunc(spaHandler.ServeHTTP)),
)
// 滑动续签:对全部路由生效(中间件自行跳过无 Bearer 头的请求)
server.Use(handler.RenewalMiddleware(svcCtx))
defer server.Stop()
// 鉴权/系统管理 + 生产业务 + 内部 API/看板
handler.RegisterRoutes(server, svcCtx)
handler.RegisterProductionRoutes(server, svcCtx)
fmt.Printf("Starting bj_power_mes server at %s:%d...\n", c.Host, c.Port)
logx.Infof("Starting bj_power_mes server at %s:%d...", c.Host, c.Port)
// 服务起来后自动打开浏览器访问前端
host := c.Host
if host == "0.0.0.0" || host == "" {
host = "127.0.0.1"
}
go func() {
time.Sleep(time.Second)
openBrowser(fmt.Sprintf("http://%s:%d", host, c.Port))
}()
server.Start()
}