chore: init bj_power monorepo (dashboard/mes/wms/wms_client/workstation), clear subproject git metadata and align naming to folder names

This commit is contained in:
SunYF
2026-08-27 10:09:54 +08:00
commit 1f0ee844a4
408 changed files with 102201 additions and 0 deletions
+238
View File
@@ -0,0 +1,238 @@
//go:build windows
package main
import (
"embed"
"errors"
"flag"
"fmt"
"io/fs"
"log/slog"
"net/http"
"os"
"os/exec"
"os/signal"
"path/filepath"
"syscall"
"time"
"bj_power_mes/internal/handler"
"bj_power_mes/internal/middleware"
xhttp "bj_power_mes/common/httpx"
xlog "bj_power_mes/common/logx"
"bj_power_mes/internal/config"
"bj_power_mes/internal/svc"
"github.com/dromara/carbon/v2"
"github.com/getlantern/systray"
"github.com/pkg/browser"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest"
"github.com/zeromicro/go-zero/rest/httpx"
"golang.org/x/sys/windows"
)
const AppName = "bj_power_mes"
var configFile = flag.String("f", "etc/bj_power_mes-api.yaml", "the config file")
var AppPath, _ = filepath.Abs(os.Args[0])
var baseUrl string
//go:embed public
var public embed.FS
//go:embed app.ico
var icon []byte
func main() {
flag.Parse()
// 业务影å“:所有时间显示使用北京时é—? carbon.SetDefault(carbon.Default{
Layout: carbon.DateTimeLayout,
Timezone: carbon.PRC,
Locale: "zh-CN",
WeekStartsAt: carbon.Monday,
})
var c config.Config
conf.MustLoad(*configFile, &c)
baseUrl = fmt.Sprintf("http://127.0.0.1:%d", c.Port)
logger := xlog.NewLogger(c.Logger)
xlog.SetDefault(logger)
logx.SetWriter(logger)
// 业务影å“ï¼šé˜²æ­¢åŒæ—¶å¯åŠ¨å¤šä¸ªå®žä¾‹ï¼Œé¿å…端å£å†²çªå’?PLC 连接冲çª
mutex, err := createMutex(AppName)
if err != nil {
if errors.Is(err, ErrAlreadyExists) {
_ = browser.OpenURL(baseUrl)
return
}
MessageBox("错误", err.Error())
return
}
defer procCloseHandle.Call(mutex)
// 业务影å“:首次è¿è¡Œæ—¶è‡ªåŠ¨åˆ›å»ºæ¡Œé¢å’Œå¼€å§‹èœå•å¿«æ·æ–¹å¼? createShortcuts()
// 业务影å“:自动写入注册表开机å¯åŠ¨ï¼Œæ— éœ€ç”¨æˆ·æ‰‹åŠ¨å‹¾é€? if err := setAutoStart(AppName, AppPath); err != nil {
slog.Warn("开机å¯åŠ¨è®¾ç½®å¤±è´? " + err.Error())
}
// 业务影å“:åˆå§‹åŒ–æ•°æ®åº“连接ã€PLC 连接
svcCtx := svc.NewServiceContext(c)
spaHandler := xhttp.NewNotFoundHandler(http.FS(mustSub(public, "public")))
server := rest.MustNewServer(
c.RestConf,
rest.WithCors("*"),
rest.WithNotFoundHandler(spaHandler),
)
logx.DisableStat()
logx.SetWriter(logger)
defer server.Stop()
handler.RegisterHandlers(server, svcCtx)
// 写æ“作审计中间件(兜底覆盖系统管ç†ç±» CRUD 等所有写接å£ï¼? server.Use(middleware.WriteAudit(svcCtx))
// 业务影å“:统一错误å“应格å¼ï¼Œå‰ç«¯ä¸ç”¨å¤„ç†å¤šç§é”™è¯¯æ ¼å¼? httpx.SetValidator(xhttp.NewValidator())
httpx.SetOkHandler(xhttp.OkJsonCtx)
httpx.SetErrorHandlerCtx(xhttp.ErrorCtx)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
slog.Info(fmt.Sprintf("Starting server at %s:%d...", c.Host, c.Port))
go server.Start()
// 等待æœåС噍å¯åŠ¨å®ŒæˆåŽå†æ‰“å¼€æµè§ˆå™¨ï¼Œé¿å… 404
go func() {
for i := 0; i < 50; i++ {
resp, err := http.Get(baseUrl)
if err == nil {
resp.Body.Close()
_ = browser.OpenURL(baseUrl)
return
}
time.Sleep(200 * time.Millisecond)
}
slog.Warn("server å¯åŠ¨è¶…æ—¶ï¼Œè·³è¿‡è‡ªåŠ¨æ‰“å¼€æµè§ˆå™?)
}()
// 业务影å“:Windows åŽå°è¿è¡Œï¼Œé€šè¿‡æ‰˜ç›˜å›¾æ ‡æŽ§åˆ¶é€€å‡?打开网页
systray.Run(onReady, func() {
slog.Info("onExit")
})
}
func mustSub(fsFS embed.FS, dir string) fs.FS {
sub, err := fs.Sub(fsFS, dir)
if err != nil {
panic(err)
}
return sub
}
// onReady ç³»ç»Ÿæ‰˜ç›˜ï¼šç”¨æˆ·å¯æ‰“开网页ã€åˆ‡æ¢å¼€æœºè‡ªå¯ï¼ˆéœ€ç®¡ç†å‘˜æƒé™ï¼‰ã€é€€å‡ºç¨‹åº?func onReady() {
systray.SetIcon(icon)
systray.SetTemplateIcon(icon, icon)
systray.SetTitle("åŒäº¬çµåŠç®¡æŽ§ç³»ç»Ÿ")
systray.SetTooltip("åŒäº¬çµåŠç®¡æŽ§ç³»ç»Ÿ")
mOpen := systray.AddMenuItem("æå¼ç®¡ç页é¢", "")
systray.AddSeparator()
mAutoStart := systray.AddMenuItem("弿œºå¯åŠ?, "")
mQuit := systray.AddMenuItem("退å‡?, "éåºæœåŠ?)
// 业务影å“ï¼šè¯»å–æ³¨å†Œè¡¨æ¢å¤ä¸Šæ¬¡çš„开机å¯åŠ¨è®¾ç½®çŠ¶æ€? if isAutoStartEnabled(AppName) {
mAutoStart.Check()
}
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
go func() {
for {
select {
case s := <-signalChan:
slog.Info("receive signal: " + s.String())
systray.Quit()
return
case <-mQuit.ClickedCh:
systray.Quit()
return
case <-mOpen.ClickedCh:
err := browser.OpenURL(baseUrl)
if err != nil {
logx.Error(err.Error())
}
case <-mAutoStart.ClickedCh:
if mAutoStart.Checked() {
if err := removeAutoStart(AppName); err != nil {
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
MessageBox("错误", "请用管ç†å‘˜æƒé™è¿è¡Œæ­¤ç¨‹åºã€?)
} else {
MessageBox("é误", err.Error())
}
slog.Error("设置失败�" + err.Error())
} else {
mAutoStart.Uncheck()
slog.Info("å·²ç»æˆåŠŸåæˆèªåЍè¿è¡Œã?)
}
} else {
if err := setAutoStart(AppName, AppPath); err != nil {
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
MessageBox("错误", "请用管ç†å‘˜æƒé™è¿è¡Œæ­¤ç¨‹åºã€?)
} else {
MessageBox("é误", err.Error())
}
slog.Error("设置失败�" + err.Error())
} else {
mAutoStart.Check()
slog.Info("å·²ç»æˆåŠŸè®¾ç½®ä¸ºèªåЍè¿è¡Œã?)
}
}
}
}
}()
}
// createShortcuts 首次è¿è¡Œæ—¶è‡ªåŠ¨åˆ›å»ºæ¡Œé¢å’Œå¼€å§‹èœå•å¿«æ·æ–¹å¼ã€?// å¦‚æžœå¿«æ·æ–¹å¼å·²å­˜åœ¨åˆ™è·³è¿‡ï¼Œåˆ›å»ºå¤±è´¥ä¸é˜»å¡žç¨‹åºå¯åЍã€?func createShortcuts() {
shortcutName := "北京电力管控系统"
exePath, err := os.Executable()
if err != nil {
return
}
exeDir := filepath.Dir(exePath)
iconPath := filepath.Join(exeDir, "app.ico")
// 桌é¢å¿«æ·æ–¹å¼
desktopDir, _ := os.UserHomeDir()
desktopPath := filepath.Join(desktopDir, "Desktop", shortcutName+".lnk")
makeShortcut(desktopPath, exePath, exeDir, iconPath)
// 开始èœå•å¿«æ·æ–¹å¼? startMenuPath := filepath.Join(os.Getenv("APPDATA"),
"Microsoft", "Windows", "Start Menu", "Programs", shortcutName+".lnk")
makeShortcut(startMenuPath, exePath, exeDir, iconPath)
}
// makeShortcut 通过 PowerShell 创建 .lnk å¿«æ·æ–¹å¼ã€?// 如果文件已存在则跳过,创建失败ä¸é˜»å¡žã€?func makeShortcut(shortcutPath, targetPath, workDir, iconPath string) {
if _, err := os.Stat(shortcutPath); err == nil {
return // 已存在,跳过
}
script := fmt.Sprintf(
`$s=(New-Object -ComObject WScript.Shell).CreateShortcut('%s');$s.TargetPath='%s';$s.WorkingDirectory='%s';$s.IconLocation='%s';$s.Save()`,
shortcutPath, targetPath, workDir, iconPath,
)
cmd := exec.Command("powershell", "-ExecutionPolicy", "Bypass", "-NoProfile", "-Command", script)
_ = cmd.Run() // 创建失败ä¸é˜»å¡žå¯åŠ?}