改为可视化界面
This commit is contained in:
parent
f538608ba4
commit
8fd7ec0d15
16
README.md
16
README.md
@ -1,5 +1,21 @@
|
||||
# readcard-go
|
||||
|
||||
## GUI 读卡界面
|
||||
|
||||
双击打包后的 `readcard-go.exe` 会启动桌面读卡界面和后台 HTTP 服务。点击“读卡”后,成功时显示二维码,内容格式为:
|
||||
|
||||
```text
|
||||
encodeURIComponent(Name)|IDNum|CardNum|CardIDCode
|
||||
```
|
||||
|
||||
失败时错误原因显示在二维码下方。GUI 默认使用杭州免 PIN 读卡器类型,可在 `config.json` 中修改:
|
||||
|
||||
```json
|
||||
"gui_reader_type": "ZJ_HZ_310000"
|
||||
```
|
||||
|
||||
Windows Common Controls v6 清单已通过 `rsrc_windows_386.syso` 嵌入 EXE,用于避免 GUI 启动时出现 `TTM_ADDTOOL failed`。`readcard-go.exe.manifest` 是资源的源文件;如修改该文件,需要重新生成对应的 `.syso` 资源。
|
||||
|
||||
`card-read-service` 的 Go 版本,保持原有 HTTP 接口和响应格式,并增加业务失败、panic、DLL 崩溃与异常退出日志。
|
||||
|
||||
## 构建和运行
|
||||
|
||||
@ -8,6 +8,11 @@ $ProjectRoot = $PSScriptRoot
|
||||
$DistDir = Join-Path $ProjectRoot "dist"
|
||||
$VendorSource = Join-Path $ProjectRoot "..\card-read-service\package\DWCardReaderDLL"
|
||||
$VendorTarget = Join-Path $DistDir "package\DWCardReaderDLL"
|
||||
$ResourceFile = Join-Path $ProjectRoot "rsrc_windows_386.syso"
|
||||
|
||||
if (-not (Test-Path -LiteralPath $ResourceFile)) {
|
||||
throw "Missing embedded Windows resource: $ResourceFile"
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $DistDir | Out-Null
|
||||
|
||||
@ -26,7 +31,7 @@ try {
|
||||
throw "Windows 386 tests failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
go build -buildvcs=false -trimpath -ldflags "-s -w -X main.version=$Version" -o (Join-Path $DistDir "readcard-go.exe") .
|
||||
go build -buildvcs=false -trimpath -ldflags "-s -w -H windowsgui -X main.version=$Version" -o (Join-Path $DistDir "readcard-go.exe") .
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Windows 386 build failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ type Config struct {
|
||||
LogMaxTotalMB int `json:"log_max_total_mb"`
|
||||
RestartDelayMS int `json:"restart_delay_ms"`
|
||||
MaxRapidRestarts int `json:"max_rapid_restarts"`
|
||||
GUIReaderType string `json:"gui_reader_type"`
|
||||
AppRoot string `json:"-"`
|
||||
}
|
||||
|
||||
@ -36,6 +37,7 @@ func defaultConfig(appRoot string) Config {
|
||||
LogMaxTotalMB: 200,
|
||||
RestartDelayMS: 1500,
|
||||
MaxRapidRestarts: 5,
|
||||
GUIReaderType: "ZJ_HZ_310000",
|
||||
AppRoot: appRoot,
|
||||
}
|
||||
}
|
||||
@ -96,6 +98,9 @@ func loadConfigAt(root string) (Config, error) {
|
||||
if value := strings.TrimSpace(os.Getenv("CARD_DLL_DIR")); value != "" {
|
||||
cfg.DLLDir = value
|
||||
}
|
||||
if value := strings.TrimSpace(os.Getenv("CARD_GUI_READER_TYPE")); value != "" {
|
||||
cfg.GUIReaderType = value
|
||||
}
|
||||
if value := os.Getenv("CARD_CORS_ORIGIN"); value != "" {
|
||||
cfg.CORSOrigin = value
|
||||
}
|
||||
@ -124,6 +129,9 @@ func loadConfigAt(root string) (Config, error) {
|
||||
if strings.TrimSpace(cfg.DLLDir) == "" {
|
||||
return Config{}, errors.New("dll_dir 不能为空")
|
||||
}
|
||||
if strings.TrimSpace(cfg.GUIReaderType) == "" {
|
||||
return Config{}, errors.New("gui_reader_type 不能为空")
|
||||
}
|
||||
if strings.TrimSpace(cfg.CORSOrigin) == "" {
|
||||
cfg.CORSOrigin = "*"
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
"host": "127.0.0.1",
|
||||
"port": 17880,
|
||||
"dll_dir": "package/DWCardReaderDLL",
|
||||
"gui_reader_type": "ZJ_HZ_310000",
|
||||
"cors_origin": "*",
|
||||
"log_dir": "logs",
|
||||
"log_retention_days": 30,
|
||||
|
||||
@ -18,7 +18,7 @@ func TestLoadConfigDefaults(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cfg.Port != 17880 || !filepath.IsAbs(cfg.LogDir) {
|
||||
if cfg.Port != 17880 || cfg.GUIReaderType != "ZJ_HZ_310000" || !filepath.IsAbs(cfg.LogDir) {
|
||||
t.Fatalf("unexpected config: %#v", cfg)
|
||||
}
|
||||
}
|
||||
|
||||
10
go.mod
10
go.mod
@ -2,3 +2,13 @@ module readcard-go
|
||||
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect
|
||||
)
|
||||
|
||||
11
go.sum
Normal file
11
go.sum
Normal file
@ -0,0 +1,11 @@
|
||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794 h1:NVRJ0Uy0SOFcXSKLsS65OmI1sgCCfiDUPj+cwnH7GZw=
|
||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc=
|
||||
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
|
||||
225
gui.go
Normal file
225
gui.go
Normal file
@ -0,0 +1,225 @@
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/lxn/walk"
|
||||
. "github.com/lxn/walk/declarative"
|
||||
"github.com/lxn/win"
|
||||
qrcode "github.com/skip2/go-qrcode"
|
||||
)
|
||||
|
||||
type guiAPIResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
type guiCardData struct {
|
||||
Name string `json:"Name"`
|
||||
IDNum string `json:"IDNum"`
|
||||
CardNum string `json:"CardNum"`
|
||||
CardIDCode string `json:"CardIDCode"`
|
||||
}
|
||||
|
||||
func runGUIProcess() int {
|
||||
cfg, err := loadConfig()
|
||||
if err != nil {
|
||||
walk.MsgBox(nil, "读卡程序", err.Error(), walk.MsgBoxIconError)
|
||||
return 1
|
||||
}
|
||||
if err = runGUI(cfg); err != nil {
|
||||
walk.MsgBox(nil, "读卡程序", err.Error(), walk.MsgBoxIconError)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func runGUI(cfg Config) error {
|
||||
var window *walk.MainWindow
|
||||
var qrView *walk.ImageView
|
||||
var message *walk.Label
|
||||
var readButton *walk.PushButton
|
||||
var currentBitmap *walk.Bitmap
|
||||
|
||||
setMessage := func(text string, isError bool) {
|
||||
message.SetText(text)
|
||||
if isError {
|
||||
message.SetTextColor(walk.RGB(196, 43, 28))
|
||||
} else {
|
||||
message.SetTextColor(walk.RGB(90, 98, 108))
|
||||
}
|
||||
}
|
||||
|
||||
readCard := func() {
|
||||
readButton.SetEnabled(false)
|
||||
readButton.SetText("正在读卡…")
|
||||
_ = qrView.SetImage(nil)
|
||||
if currentBitmap != nil {
|
||||
currentBitmap.Dispose()
|
||||
currentBitmap = nil
|
||||
}
|
||||
setMessage("请保持卡片位置不动", false)
|
||||
go func() {
|
||||
card, failure := requestCard(cfg)
|
||||
var qrImage image.Image
|
||||
if failure == nil {
|
||||
content := buildQRContent(card)
|
||||
if strings.Trim(content, "|") == "" {
|
||||
failure = fmt.Errorf("读卡成功,但未获取到有效卡片信息")
|
||||
} else {
|
||||
code, qrErr := qrcode.New(content, qrcode.Medium)
|
||||
if qrErr != nil {
|
||||
failure = fmt.Errorf("生成二维码失败:%w", qrErr)
|
||||
} else {
|
||||
qrImage = code.Image(300)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.Synchronize(func() {
|
||||
defer func() {
|
||||
readButton.SetEnabled(true)
|
||||
readButton.SetText("读卡")
|
||||
}()
|
||||
if failure != nil {
|
||||
setMessage(failure.Error(), true)
|
||||
return
|
||||
}
|
||||
bitmap, bitmapErr := walk.NewBitmapFromImage(qrImage)
|
||||
if bitmapErr != nil {
|
||||
setMessage("显示二维码失败:"+bitmapErr.Error(), true)
|
||||
return
|
||||
}
|
||||
if err := qrView.SetImage(bitmap); err != nil {
|
||||
bitmap.Dispose()
|
||||
setMessage("显示二维码失败:"+err.Error(), true)
|
||||
return
|
||||
}
|
||||
if currentBitmap != nil {
|
||||
currentBitmap.Dispose()
|
||||
}
|
||||
currentBitmap = bitmap
|
||||
setMessage("读卡成功,请扫描二维码", false)
|
||||
})
|
||||
}()
|
||||
}
|
||||
|
||||
windowDef := MainWindow{
|
||||
AssignTo: &window,
|
||||
Title: "社保卡读卡",
|
||||
Size: Size{520, 590},
|
||||
MinSize: Size{520, 590},
|
||||
MaxSize: Size{520, 590},
|
||||
Background: SolidColorBrush{Color: walk.RGB(247, 249, 252)},
|
||||
Layout: VBox{MarginsZero: true, SpacingZero: true},
|
||||
Children: []Widget{
|
||||
Composite{
|
||||
Layout: VBox{Margins: Margins{24, 22, 24, 12}, Spacing: 12},
|
||||
Children: []Widget{
|
||||
Label{Text: "社保卡读卡", Font: Font{Family: "Microsoft YaHei UI", PointSize: 16, Bold: true}, TextColor: walk.RGB(30, 38, 50)},
|
||||
ImageView{AssignTo: &qrView, MinSize: Size{320, 320}, Mode: ImageViewModeCenter, Background: SolidColorBrush{Color: walk.RGB(255, 255, 255)}},
|
||||
Label{AssignTo: &message, Text: "请放置社保卡,然后点击读卡", Font: Font{Family: "Microsoft YaHei UI", PointSize: 10}, Alignment: AlignHCenterVCenter, TextAlignment: AlignCenter, MinSize: Size{0, 52}, TextColor: walk.RGB(90, 98, 108)},
|
||||
},
|
||||
},
|
||||
Composite{
|
||||
Background: SolidColorBrush{Color: walk.RGB(255, 255, 255)},
|
||||
Layout: HBox{Margins: Margins{24, 18, 24, 18}},
|
||||
Children: []Widget{
|
||||
HSpacer{},
|
||||
PushButton{AssignTo: &readButton, Text: "读卡", MinSize: Size{150, 44}, Font: Font{Family: "Microsoft YaHei UI", PointSize: 11, Bold: true}, OnClicked: readCard},
|
||||
HSpacer{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := windowDef.Create(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Keep only the requested minimize and close buttons in the title bar.
|
||||
style := win.GetWindowLong(window.Handle(), win.GWL_STYLE)
|
||||
win.SetWindowLong(window.Handle(), win.GWL_STYLE, style&^win.WS_MAXIMIZEBOX)
|
||||
defer func() {
|
||||
if currentBitmap != nil {
|
||||
currentBitmap.Dispose()
|
||||
}
|
||||
window.Dispose()
|
||||
}()
|
||||
window.Run()
|
||||
return nil
|
||||
}
|
||||
|
||||
func requestCard(cfg Config) (guiCardData, error) {
|
||||
body, _ := json.Marshal(map[string]string{"reader_type": cfg.GUIReaderType})
|
||||
client := &http.Client{Timeout: 2 * time.Minute}
|
||||
host := cfg.Host
|
||||
if host == "0.0.0.0" || host == "::" {
|
||||
host = "127.0.0.1"
|
||||
}
|
||||
url := fmt.Sprintf("http://%s:%d/api/card/read-nopin", host, cfg.Port)
|
||||
var lastErr error
|
||||
for attempt := 0; attempt < 8; attempt++ {
|
||||
response, err := client.Post(url, "application/json", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
defer response.Body.Close()
|
||||
var payload guiAPIResponse
|
||||
if err = json.NewDecoder(response.Body).Decode(&payload); err != nil {
|
||||
return guiCardData{}, fmt.Errorf("读卡服务返回格式错误:%w", err)
|
||||
}
|
||||
if response.StatusCode != http.StatusOK || payload.Code != 0 {
|
||||
if strings.TrimSpace(payload.Message) == "" {
|
||||
payload.Message = fmt.Sprintf("读卡失败(状态码 %d)", response.StatusCode)
|
||||
}
|
||||
return guiCardData{}, fmt.Errorf("%s", payload.Message)
|
||||
}
|
||||
var card guiCardData
|
||||
if err = json.Unmarshal(payload.Data, &card); err != nil {
|
||||
return guiCardData{}, fmt.Errorf("无法解析卡片信息:%w", err)
|
||||
}
|
||||
return card, nil
|
||||
}
|
||||
return guiCardData{}, fmt.Errorf("无法连接读卡服务:%v", lastErr)
|
||||
}
|
||||
|
||||
func buildQRContent(card guiCardData) string {
|
||||
return encodeURIComponent(card.Name) + "|" + card.IDNum + "|" + card.CardNum + "|" + card.CardIDCode
|
||||
}
|
||||
|
||||
// encodeURIComponent matches JavaScript's encodeURIComponent for UTF-8 text.
|
||||
func encodeURIComponent(value string) string {
|
||||
const hex = "0123456789ABCDEF"
|
||||
var result strings.Builder
|
||||
result.Grow(len(value))
|
||||
for len(value) > 0 {
|
||||
r, size := utf8.DecodeRuneInString(value)
|
||||
if r == utf8.RuneError && size == 1 {
|
||||
r = '\uFFFD'
|
||||
}
|
||||
encoded := make([]byte, utf8.RuneLen(r))
|
||||
utf8.EncodeRune(encoded, r)
|
||||
for _, b := range encoded {
|
||||
if (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') || strings.ContainsRune("-_.!~*'()", rune(b)) {
|
||||
result.WriteByte(b)
|
||||
} else {
|
||||
result.WriteByte('%')
|
||||
result.WriteByte(hex[b>>4])
|
||||
result.WriteByte(hex[b&15])
|
||||
}
|
||||
}
|
||||
value = value[size:]
|
||||
}
|
||||
return result.String()
|
||||
}
|
||||
21
gui_test.go
Normal file
21
gui_test.go
Normal file
@ -0,0 +1,21 @@
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestBuildQRContent(t *testing.T) {
|
||||
got := buildQRContent(guiCardData{Name: "张 三", IDNum: "3301", CardNum: "C-1", CardIDCode: "ID"})
|
||||
want := "%E5%BC%A0%20%E4%B8%89|3301|C-1|ID"
|
||||
if got != want {
|
||||
t.Fatalf("buildQRContent() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeURIComponentCompatibleCharacters(t *testing.T) {
|
||||
const input = "AZaz09-_.!~*'() /"
|
||||
const want = "AZaz09-_.!~*'()%20%2F"
|
||||
if got := encodeURIComponent(input); got != want {
|
||||
t.Fatalf("encodeURIComponent() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
50
main.go
50
main.go
@ -29,24 +29,31 @@ func realMain() (exitCode int) {
|
||||
exitCode = 2
|
||||
}
|
||||
}()
|
||||
if hasArg("--gui") {
|
||||
return runGUIProcess()
|
||||
}
|
||||
if isWorker() {
|
||||
return runWorker()
|
||||
}
|
||||
return runSupervisor()
|
||||
}
|
||||
|
||||
func isWorker() bool {
|
||||
if os.Getenv("CARD_NO_SUPERVISOR") == "1" {
|
||||
return true
|
||||
}
|
||||
func hasArg(want string) bool {
|
||||
for _, arg := range os.Args[1:] {
|
||||
if arg == "--worker" {
|
||||
if arg == want {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isWorker() bool {
|
||||
if os.Getenv("CARD_NO_SUPERVISOR") == "1" {
|
||||
return true
|
||||
}
|
||||
return hasArg("--worker")
|
||||
}
|
||||
|
||||
func runWorker() int {
|
||||
cfg, err := loadConfig()
|
||||
if err != nil {
|
||||
@ -172,6 +179,22 @@ func runSupervisor() int {
|
||||
waitDone := make(chan error, 1)
|
||||
go func() { waitDone <- cmd.Wait() }()
|
||||
|
||||
gui := exec.Command(exe, "--gui")
|
||||
gui.Dir = cfg.AppRoot
|
||||
gui.Env = append(os.Environ(), "CARD_APP_ROOT="+cfg.AppRoot)
|
||||
if err = gui.Start(); err != nil {
|
||||
logger.Error("启动 GUI 失败", "event", "gui_start_failure", "error", err)
|
||||
_ = cmd.Process.Kill()
|
||||
<-waitDone
|
||||
if crashWriter != nil {
|
||||
_ = crashWriter.Close()
|
||||
}
|
||||
return 1
|
||||
}
|
||||
logger.Info("GUI 已启动", "event", "gui_started", "gui_pid", gui.Process.Pid)
|
||||
guiDone := make(chan error, 1)
|
||||
go func() { guiDone <- gui.Wait() }()
|
||||
|
||||
select {
|
||||
case sig := <-signals:
|
||||
logger.Info("守护进程收到停止信号", "event", "supervisor_shutdown", "signal", sig.String(), "worker_pid", cmd.Process.Pid)
|
||||
@ -186,8 +209,25 @@ func runSupervisor() int {
|
||||
if crashWriter != nil {
|
||||
_ = crashWriter.Close()
|
||||
}
|
||||
_ = gui.Process.Kill()
|
||||
<-guiDone
|
||||
return 0
|
||||
case guiErr := <-guiDone:
|
||||
logger.Info("GUI 已关闭", "event", "gui_stopped", "error", guiErr)
|
||||
_ = cmd.Process.Signal(os.Interrupt)
|
||||
select {
|
||||
case <-waitDone:
|
||||
case <-time.After(10 * time.Second):
|
||||
_ = cmd.Process.Kill()
|
||||
<-waitDone
|
||||
}
|
||||
if crashWriter != nil {
|
||||
_ = crashWriter.Close()
|
||||
}
|
||||
return 0
|
||||
case waitErr := <-waitDone:
|
||||
_ = gui.Process.Kill()
|
||||
<-guiDone
|
||||
if crashWriter != nil {
|
||||
_ = crashWriter.Close()
|
||||
}
|
||||
|
||||
26
readcard-go.exe.manifest
Normal file
26
readcard-go.exe.manifest
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="readcard-go"
|
||||
version="1.0.0.0"
|
||||
processorArchitecture="*" />
|
||||
<description>Social security card reader</description>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*" />
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
BIN
rsrc_windows_386.syso
Normal file
BIN
rsrc_windows_386.syso
Normal file
Binary file not shown.
12
一键打包.bat
12
一键打包.bat
@ -78,6 +78,18 @@ if not exist "%PROJECT_DIR%config.json" (
|
||||
)
|
||||
echo [OK] Configuration file
|
||||
|
||||
if not exist "%PROJECT_DIR%readcard-go.exe.manifest" (
|
||||
echo [ERROR] Missing Windows application manifest: %PROJECT_DIR%readcard-go.exe.manifest
|
||||
goto :environment_check_failed
|
||||
)
|
||||
echo [OK] Windows application manifest
|
||||
|
||||
if not exist "%PROJECT_DIR%rsrc_windows_386.syso" (
|
||||
echo [ERROR] Missing embedded Windows resource: %PROJECT_DIR%rsrc_windows_386.syso
|
||||
goto :environment_check_failed
|
||||
)
|
||||
echo [OK] Embedded Windows resource
|
||||
|
||||
if not exist "%VENDOR_DLL%" (
|
||||
echo [ERROR] Vendor DLL was not found:
|
||||
echo %VENDOR_DLL%
|
||||
|
||||
10
一键打包.sh
10
一键打包.sh
@ -56,6 +56,14 @@ printf '%s\n' "[OK] Go module file"
|
||||
[ -f "$PROJECT_DIR/config.json" ] || fail "Missing configuration file: $PROJECT_DIR/config.json"
|
||||
printf '%s\n' "[OK] Configuration file"
|
||||
|
||||
[ -f "$PROJECT_DIR/readcard-go.exe.manifest" ] || fail \
|
||||
"Missing Windows application manifest: $PROJECT_DIR/readcard-go.exe.manifest"
|
||||
printf '%s\n' "[OK] Windows application manifest"
|
||||
|
||||
[ -f "$PROJECT_DIR/rsrc_windows_386.syso" ] || fail \
|
||||
"Missing embedded Windows resource: $PROJECT_DIR/rsrc_windows_386.syso"
|
||||
printf '%s\n' "[OK] Embedded Windows resource"
|
||||
|
||||
[ -f "$VENDOR_DLL" ] || fail \
|
||||
"Vendor DLL was not found: $VENDOR_DLL. Restore card-read-service/package/DWCardReaderDLL before packaging."
|
||||
printf '%s\n' "[OK] Vendor DLL package"
|
||||
@ -82,7 +90,7 @@ GOOS=windows GOARCH=386 CGO_ENABLED=0 \
|
||||
go build \
|
||||
-buildvcs=false \
|
||||
-trimpath \
|
||||
-ldflags "-s -w -X main.version=$BUILD_VERSION" \
|
||||
-ldflags "-s -w -H windowsgui -X main.version=$BUILD_VERSION" \
|
||||
-o "$TMP_BUILD_DIR/readcard-go.exe" \
|
||||
.
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user