commit 95d3a20292a6c057e891d5d522f495105c2ad1fa
Author: 绝尘 <237809796@qq.com>
Date: Tue Dec 30 20:27:35 2025 +0800
.
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d5ee323
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+# Wails 自动生成的绑定代码
+frontend/
+web/src/wailsjs/
+
+# 构建产物
+build/bin/
+web/dist/
+
+# 依赖目录
+web/node_modules/
+web/bun.lock
+
+# Go 相关
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+*.test
+*.out
+go.work
+
+# IDE
+.idea/
+.vscode/
+*.swp
+*.swo
+*~
+
+# 系统文件
+.DS_Store
+Thumbs.db
+
+# 日志文件
+*.log
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..60075a2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,117 @@
+# Go Desk
+
+基于 Wails 的桌面应用程序,用于测试验证技术栈。
+
+## 技术栈
+
+- Go v1.25.4
+- Wails v2
+- Vue 3
+- Arco Design Vue
+- MySQL (lab_dev)
+
+## 项目结构
+
+```
+go-desk/
+├── app.go # 应用逻辑,暴露给前端的方法
+├── main.go # 程序入口
+├── wails.json # Wails 配置
+├── go.mod # Go 模块依赖
+├── internal/
+│ ├── database/ # 数据库连接
+│ │ └── db.go
+│ └── model/ # 数据模型
+│ └── member_info.go
+└── web/ # 前端代码
+ ├── package.json
+ ├── vite.config.js
+ ├── index.html
+ └── src/
+ ├── main.js
+ ├── App.vue
+ └── style.css
+```
+
+## 开发
+
+### 1. 安装依赖
+
+```bash
+# Go 依赖
+go mod tidy
+
+# 前端依赖
+cd web
+npm install
+```
+
+### 2. 构建前端(必须)
+
+```bash
+cd web
+npm run build
+```
+
+**重要**:每次修改前端代码后都需要重新构建,Wails 使用 `web/dist` 目录中的构建产物。
+
+### 3. 开发模式运行
+
+```bash
+# 在项目根目录
+wails dev
+```
+
+**注意**:如果 `wails` 命令找不到,使用完整路径:
+```bash
+# 获取 GOPATH
+go env GOPATH
+
+# 使用完整路径(根据你的 GOPATH 调整)
+D:\Go\go-workspace\bin\wails.exe dev
+```
+
+### 4. 构建应用
+
+```bash
+# 确保前端已构建
+cd web
+npm run build
+cd ..
+
+# 构建当前平台
+wails build
+
+# 构建 Windows(明确指定平台)
+wails build -platform windows/amd64
+```
+
+**构建产物位置**:`build/bin/go-desk.exe`
+
+**注意**:
+- 构建前确保前端已构建(`web/dist` 目录存在)
+- 构建产物是独立的可执行文件,包含前端资源
+- 首次运行需要确保 MySQL 数据库可访问
+
+## 数据库配置
+
+- 数据库:MySQL lab_dev
+- 测试服连接:39.99.243.191:3306, root/Lake@2019
+- 表:member_info
+
+## 功能
+
+- [x] 用户查询展示
+- [x] 关键字搜索
+- [x] 状态筛选
+- [x] 分页显示
+- [ ] 角色筛选(待完善)
+- [ ] 机构筛选(待完善)
+- [ ] 关联查询机构名称和角色名称
+
+## 注意事项
+
+1. 首次运行前需要先构建前端:`cd web && npm run build`
+2. 确保 MySQL 数据库 lab_dev 已启动
+3. 确保 member_info 表存在
+
diff --git a/app.go b/app.go
new file mode 100644
index 0000000..771dfe7
--- /dev/null
+++ b/app.go
@@ -0,0 +1,122 @@
+package main
+
+import (
+ "context"
+ "go-desk/internal/database"
+ "go-desk/internal/filesystem"
+ "go-desk/internal/system"
+ "os"
+)
+
+// App 应用结构体
+type App struct {
+ ctx context.Context
+ db *database.DB
+}
+
+// NewApp 创建新的应用实例
+func NewApp() *App {
+ return &App{}
+}
+
+// startup 应用启动时调用
+func (a *App) startup(ctx context.Context) {
+ a.ctx = ctx
+
+ // 初始化数据库连接
+ db, err := database.Init()
+ if err != nil {
+ println("数据库连接失败:", err.Error())
+ return
+ }
+ a.db = db
+}
+
+// QueryUsers 查询用户列表
+func (a *App) QueryUsers(keyword string, status int, role int, organid int, page int, pageSize int, sortField string, sortOrder string) (map[string]interface{}, error) {
+ if a.db == nil {
+ return map[string]interface{}{
+ "rows": []interface{}{},
+ "total": 0,
+ }, nil
+ }
+
+ return a.db.QueryUsers(keyword, status, role, organid, page, pageSize, sortField, sortOrder)
+}
+
+// Greet 测试方法
+func (a *App) Greet(name string) string {
+ return "Hello " + name + ", It's show time!"
+}
+
+// GetSystemInfo 获取系统信息
+func (a *App) GetSystemInfo() (map[string]interface{}, error) {
+ return system.GetSystemInfo()
+}
+
+// GetCPUInfo 获取 CPU 信息
+func (a *App) GetCPUInfo() (map[string]interface{}, error) {
+ return system.GetCPUInfo()
+}
+
+// GetMemoryInfo 获取内存信息
+func (a *App) GetMemoryInfo() (map[string]interface{}, error) {
+ return system.GetMemoryInfo()
+}
+
+// GetDiskInfo 获取磁盘信息
+func (a *App) GetDiskInfo() ([]map[string]interface{}, error) {
+ return system.GetDiskInfo()
+}
+
+// ReadFile 读取文件
+func (a *App) ReadFile(path string) (string, error) {
+ return filesystem.ReadFile(path)
+}
+
+// WriteFile 写入文件
+func (a *App) WriteFile(path, content string) error {
+ return filesystem.WriteFile(path, content)
+}
+
+// ListDir 列出目录
+func (a *App) ListDir(path string) ([]map[string]interface{}, error) {
+ return filesystem.ListDir(path)
+}
+
+// CreateDir 创建目录
+func (a *App) CreateDir(path string) error {
+ return filesystem.CreateDir(path)
+}
+
+// DeletePath 删除文件或目录
+func (a *App) DeletePath(path string) error {
+ return filesystem.DeletePath(path)
+}
+
+// GetFileInfo 获取文件信息
+func (a *App) GetFileInfo(path string) (map[string]interface{}, error) {
+ return filesystem.GetFileInfo(path)
+}
+
+// GetEnvVars 获取环境变量
+func (a *App) GetEnvVars() (map[string]string, error) {
+ envVars := make(map[string]string)
+ for _, env := range os.Environ() {
+ parts := splitEnv(env)
+ if len(parts) == 2 {
+ envVars[parts[0]] = parts[1]
+ }
+ }
+ return envVars, nil
+}
+
+// splitEnv 分割环境变量字符串(key=value)
+func splitEnv(env string) []string {
+ for i := 0; i < len(env); i++ {
+ if env[i] == '=' {
+ return []string{env[:i], env[i+1:]}
+ }
+ }
+ return []string{env}
+}
diff --git a/build/appicon.png b/build/appicon.png
new file mode 100644
index 0000000..63617fe
Binary files /dev/null and b/build/appicon.png differ
diff --git a/build/windows/icon.ico b/build/windows/icon.ico
new file mode 100644
index 0000000..bfa0690
Binary files /dev/null and b/build/windows/icon.ico differ
diff --git a/build/windows/info.json b/build/windows/info.json
new file mode 100644
index 0000000..9727946
--- /dev/null
+++ b/build/windows/info.json
@@ -0,0 +1,15 @@
+{
+ "fixed": {
+ "file_version": "{{.Info.ProductVersion}}"
+ },
+ "info": {
+ "0000": {
+ "ProductVersion": "{{.Info.ProductVersion}}",
+ "CompanyName": "{{.Info.CompanyName}}",
+ "FileDescription": "{{.Info.ProductName}}",
+ "LegalCopyright": "{{.Info.Copyright}}",
+ "ProductName": "{{.Info.ProductName}}",
+ "Comments": "{{.Info.Comments}}"
+ }
+ }
+}
\ No newline at end of file
diff --git a/build/windows/wails.exe.manifest b/build/windows/wails.exe.manifest
new file mode 100644
index 0000000..17e1a23
--- /dev/null
+++ b/build/windows/wails.exe.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+ true/pm
+ permonitorv2,permonitor
+
+
+
\ No newline at end of file
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..385eb29
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,50 @@
+module go-desk
+
+go 1.25.4
+
+require (
+ github.com/go-sql-driver/mysql v1.8.1
+ github.com/shirou/gopsutil/v3 v3.24.5
+ github.com/wailsapp/wails/v2 v2.11.0
+ gorm.io/driver/mysql v1.6.0
+ gorm.io/gorm v1.31.0
+)
+
+require (
+ filippo.io/edwards25519 v1.1.0 // indirect
+ github.com/bep/debounce v1.2.1 // indirect
+ github.com/go-ole/go-ole v1.3.0 // indirect
+ github.com/godbus/dbus/v5 v5.1.0 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/websocket v1.5.3 // indirect
+ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
+ github.com/jinzhu/inflection v1.0.0 // indirect
+ github.com/jinzhu/now v1.1.5 // indirect
+ github.com/labstack/echo/v4 v4.13.3 // indirect
+ github.com/labstack/gommon v0.4.2 // indirect
+ github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
+ github.com/leaanthony/gosod v1.0.4 // indirect
+ github.com/leaanthony/slicer v1.6.0 // indirect
+ github.com/leaanthony/u v1.1.1 // indirect
+ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
+ github.com/samber/lo v1.49.1 // indirect
+ github.com/shoenig/go-m1cpu v0.1.6 // indirect
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
+ github.com/tklauser/numcpus v0.6.1 // indirect
+ github.com/tkrajina/go-reflector v0.5.8 // indirect
+ github.com/valyala/bytebufferpool v1.0.0 // indirect
+ github.com/valyala/fasttemplate v1.2.2 // indirect
+ github.com/wailsapp/go-webview2 v1.0.22 // indirect
+ github.com/wailsapp/mimetype v1.4.1 // indirect
+ github.com/yusufpapurcu/wmi v1.2.4 // indirect
+ golang.org/x/crypto v0.33.0 // indirect
+ golang.org/x/net v0.35.0 // indirect
+ golang.org/x/sys v0.30.0 // indirect
+ golang.org/x/text v0.22.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..96a305a
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,118 @@
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
+github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
+github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
+github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
+github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
+github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
+github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
+github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
+github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
+github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
+github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
+github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
+github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI=
+github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw=
+github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
+github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
+github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
+github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
+github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
+github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
+github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
+github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
+github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
+github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
+github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
+github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
+github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
+github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
+github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
+github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
+github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
+github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
+github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
+github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/wailsapp/go-webview2 v1.0.22 h1:YT61F5lj+GGaat5OB96Aa3b4QA+mybD0Ggq6NZijQ58=
+github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
+github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
+github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
+github.com/wailsapp/wails/v2 v2.11.0 h1:seLacV8pqupq32IjS4Y7V8ucab0WZwtK6VvUVxSBtqQ=
+github.com/wailsapp/wails/v2 v2.11.0/go.mod h1:jrf0ZaM6+GBc1wRmXsM8cIvzlg0karYin3erahI4+0k=
+github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
+github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
+golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
+golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
+gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
+gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY=
+gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
diff --git a/internal/database/db.go b/internal/database/db.go
new file mode 100644
index 0000000..58654d1
--- /dev/null
+++ b/internal/database/db.go
@@ -0,0 +1,138 @@
+package database
+
+import (
+ "errors"
+ "fmt"
+ "go-desk/internal/model"
+ "time"
+
+ mysqldriver "github.com/go-sql-driver/mysql"
+ "gorm.io/driver/mysql"
+ "gorm.io/gorm"
+ "gorm.io/gorm/logger"
+)
+
+var (
+ ErrNotConnected = errors.New("数据库未连接")
+)
+
+// DB 数据库连接封装
+type DB struct {
+ db *gorm.DB
+}
+
+var globalDB *DB
+
+// Init 初始化数据库连接
+func Init() (*DB, error) {
+ if globalDB != nil {
+ return globalDB, nil
+ }
+
+ // 数据库配置 - 测试服 lab_dev
+ // 测试机外网IP: 39.99.243.191
+ // 使用 mysqldriver.Config 结构体构建 DSN,自动处理密码中的特殊字符
+ config := mysqldriver.Config{
+ User: "root",
+ Passwd: "123456",
+ Net: "tcp",
+ Addr: "127.0.0.1:3306",
+ DBName: "lab_dev",
+ Params: map[string]string{"charset": "utf8mb4", "parseTime": "True", "loc": "Local"},
+ AllowNativePasswords: true,
+ }
+ dsn := config.FormatDSN()
+
+ // GORM 配置
+ gormConfig := &gorm.Config{
+ Logger: logger.Default.LogMode(logger.Info),
+ }
+
+ db, err := gorm.Open(mysql.Open(dsn), gormConfig)
+ if err != nil {
+ return nil, fmt.Errorf("打开数据库连接失败: %v", err)
+ }
+
+ // 获取底层 sql.DB 设置连接池参数
+ sqlDB, err := db.DB()
+ if err != nil {
+ return nil, fmt.Errorf("获取数据库实例失败: %v", err)
+ }
+
+ // 测试连接
+ if err := sqlDB.Ping(); err != nil {
+ return nil, fmt.Errorf("数据库连接测试失败: %v", err)
+ }
+
+ // 设置连接池参数
+ sqlDB.SetMaxOpenConns(25)
+ sqlDB.SetMaxIdleConns(5)
+ sqlDB.SetConnMaxLifetime(time.Duration(300) * time.Second)
+
+ globalDB = &DB{db: db}
+ return globalDB, nil
+}
+
+// QueryUsers 查询用户列表
+func (d *DB) QueryUsers(keyword string, status int, role int, organid int, page int, pageSize int, sortField string, sortOrder string) (map[string]interface{}, error) {
+ if d.db == nil {
+ return nil, ErrNotConnected
+ }
+
+ query := d.db.Model(&model.MemberInfo{})
+
+ // 关键字搜索(姓名、账号、电话)
+ if keyword != "" {
+ query = query.Where("membername LIKE ? OR account LIKE ? OR contactphone LIKE ?",
+ "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
+ }
+
+ // 状态筛选
+ if status > 0 {
+ query = query.Where("status = ?", status)
+ } else {
+ // 默认过滤删除状态
+ query = query.Where("status != ?", 3)
+ }
+
+ // 角色筛选(需要关联查询,暂时简化)
+ if role > 0 {
+ // TODO: 关联 sys_member_role 表查询
+ }
+
+ // 机构筛选
+ if organid > 0 {
+ query = query.Where("organid = ?", organid)
+ }
+
+ // 排序
+ if sortField != "" {
+ if sortOrder == "descend" || sortOrder == "desc" {
+ query = query.Order(sortField + " DESC")
+ } else {
+ query = query.Order(sortField + " ASC")
+ }
+ } else {
+ // 默认按创建时间倒序
+ query = query.Order("createtime DESC")
+ }
+
+ // 总数
+ var total int64
+ query.Count(&total)
+
+ // 分页
+ offset := (page - 1) * pageSize
+ var users []model.MemberInfo
+ if err := query.Offset(offset).Limit(pageSize).Find(&users).Error; err != nil {
+ return nil, fmt.Errorf("查询用户失败: %v", err)
+ }
+
+ // 返回结果
+ result := map[string]interface{}{
+ "rows": users,
+ "total": total,
+ }
+
+ return result, nil
+}
diff --git a/internal/filesystem/fs.go b/internal/filesystem/fs.go
new file mode 100644
index 0000000..9c873f7
--- /dev/null
+++ b/internal/filesystem/fs.go
@@ -0,0 +1,190 @@
+package filesystem
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+// ReadFile 读取文件内容
+func ReadFile(path string) (string, error) {
+ if !isSafePath(path) {
+ return "", fmt.Errorf("路径不安全")
+ }
+
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return "", fmt.Errorf("读取文件失败: %v", err)
+ }
+
+ return string(data), nil
+}
+
+// WriteFile 写入文件
+func WriteFile(path, content string) error {
+ if !isSafePath(path) {
+ return fmt.Errorf("路径不安全")
+ }
+
+ dir := filepath.Dir(path)
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ return fmt.Errorf("创建目录失败: %v", err)
+ }
+
+ if err := os.WriteFile(path, []byte(content), 0644); err != nil {
+ return fmt.Errorf("写入文件失败: %v", err)
+ }
+
+ return nil
+}
+
+// ListDir 列出目录内容
+func ListDir(path string) ([]map[string]interface{}, error) {
+ if !isSafePath(path) {
+ return nil, fmt.Errorf("路径不安全")
+ }
+
+ entries, err := os.ReadDir(path)
+ if err != nil {
+ return nil, fmt.Errorf("读取目录失败: %v", err)
+ }
+
+ var result []map[string]interface{}
+ for _, entry := range entries {
+ info, err := entry.Info()
+ if err != nil {
+ continue
+ }
+
+ fullPath := filepath.Join(path, entry.Name())
+ result = append(result, map[string]interface{}{
+ "name": entry.Name(),
+ "path": fullPath,
+ "is_dir": entry.IsDir(),
+ "size": info.Size(),
+ "mod_time": info.ModTime().Format("2006-01-02 15:04:05"),
+ })
+ }
+
+ return result, nil
+}
+
+// CreateDir 创建目录
+func CreateDir(path string) error {
+ if !isSafePath(path) {
+ return fmt.Errorf("路径不安全")
+ }
+
+ if err := os.MkdirAll(path, 0755); err != nil {
+ return fmt.Errorf("创建目录失败: %v", err)
+ }
+
+ return nil
+}
+
+// DeletePath 删除文件或目录
+func DeletePath(path string) error {
+ if !isSafePath(path) {
+ return fmt.Errorf("路径不安全")
+ }
+
+ info, err := os.Stat(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return fmt.Errorf("文件或目录不存在")
+ }
+ return fmt.Errorf("获取文件信息失败: %v", err)
+ }
+
+ if info.IsDir() {
+ if err := os.RemoveAll(path); err != nil {
+ return fmt.Errorf("删除目录失败: %v", err)
+ }
+ } else {
+ if err := os.Remove(path); err != nil {
+ return fmt.Errorf("删除文件失败: %v", err)
+ }
+ }
+
+ return nil
+}
+
+// GetFileInfo 获取文件信息
+func GetFileInfo(path string) (map[string]interface{}, error) {
+ if !isSafePath(path) {
+ return nil, fmt.Errorf("路径不安全")
+ }
+
+ info, err := os.Stat(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, fmt.Errorf("文件或目录不存在")
+ }
+ return nil, fmt.Errorf("获取文件信息失败: %v", err)
+ }
+
+ formatBytes := func(bytes int64) string {
+ const unit = 1024
+ if bytes < unit {
+ return fmt.Sprintf("%d B", bytes)
+ }
+ div, exp := int64(unit), 0
+ for n := bytes / unit; n >= unit; n /= unit {
+ div *= unit
+ exp++
+ }
+ return fmt.Sprintf("%.2f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
+ }
+
+ return map[string]interface{}{
+ "name": info.Name(),
+ "path": path,
+ "size": info.Size(),
+ "size_str": formatBytes(info.Size()),
+ "is_dir": info.IsDir(),
+ "mod_time": info.ModTime().Format("2006-01-02 15:04:05"),
+ "mode": info.Mode().String(),
+ }, nil
+}
+
+// OpenPath 打开文件或目录(使用系统默认程序)
+func OpenPath(path string) error {
+ if !isSafePath(path) {
+ return fmt.Errorf("路径不安全")
+ }
+
+ // 注意:这里需要导入 os/exec,但为了安全,暂时不实现执行命令
+ // 可以考虑使用 Wails 的 runtime 包提供的功能
+ return fmt.Errorf("打开功能暂未实现,请手动打开: %s", path)
+}
+
+// isSafePath 检查路径是否安全(防止路径遍历攻击)
+func isSafePath(path string) bool {
+ // 清理路径
+ cleanPath := filepath.Clean(path)
+
+ // 检查是否包含路径遍历
+ if strings.Contains(cleanPath, "..") {
+ return false
+ }
+
+ // Windows 下检查是否尝试访问系统关键目录
+ if runtime.GOOS == "windows" {
+ lowerPath := strings.ToLower(cleanPath)
+ // 禁止访问系统关键目录(可根据需要调整)
+ forbidden := []string{
+ "c:\\windows",
+ "c:\\program files",
+ "c:\\programdata",
+ }
+ for _, fb := range forbidden {
+ if strings.HasPrefix(lowerPath, fb) {
+ return false
+ }
+ }
+ }
+
+ return true
+}
diff --git a/internal/model/member_info.go b/internal/model/member_info.go
new file mode 100644
index 0000000..7418a82
--- /dev/null
+++ b/internal/model/member_info.go
@@ -0,0 +1,26 @@
+package model
+
+// MemberInfo 用户信息表
+type MemberInfo struct {
+ Memberid int `gorm:"primaryKey;column:memberid;type:int;comment:用户ID" json:"memberid"`
+ Membername string `gorm:"column:membername;type:varchar(100);comment:姓名" json:"membername"`
+ Account string `gorm:"column:account;type:varchar(100);comment:账号" json:"account"`
+ Password string `gorm:"column:password;type:varchar(100);comment:密码" json:"-"`
+ Contactphone string `gorm:"column:contactphone;type:varchar(50);comment:联系电话" json:"contactphone"`
+ Organid int `gorm:"column:organid;type:int;comment:所属机构ID" json:"organid"`
+ Createtime string `gorm:"column:createtime;type:varchar(50);comment:创建时间" json:"createtime"`
+ Updatetime string `gorm:"column:updatetime;type:varchar(50);comment:修改时间" json:"updatetime"`
+ Role int16 `gorm:"column:role;type:smallint;comment:角色类别" json:"role"`
+ Status int16 `gorm:"column:status;type:smallint;comment:状态 1正常 2停用 3删除" json:"status"`
+ Calluserid string `gorm:"column:calluserid;type:varchar(100);comment:坐席用户ID" json:"calluserid"`
+ Remainingexport int `gorm:"column:remainingexport;type:int;comment:本月剩余导出次数" json:"remainingexport"`
+
+ // 虚拟字段(关联查询)
+ Organname string `gorm:"-" json:"organname"` // 机构名称
+ Rolename string `gorm:"-" json:"rolename"` // 角色名称
+}
+
+// TableName 指定表名
+func (MemberInfo) TableName() string {
+ return "member_info"
+}
diff --git a/internal/system/system.go b/internal/system/system.go
new file mode 100644
index 0000000..566aafe
--- /dev/null
+++ b/internal/system/system.go
@@ -0,0 +1,145 @@
+package system
+
+import (
+ "fmt"
+ "runtime"
+
+ "github.com/shirou/gopsutil/v3/cpu"
+ "github.com/shirou/gopsutil/v3/disk"
+ "github.com/shirou/gopsutil/v3/host"
+ "github.com/shirou/gopsutil/v3/mem"
+)
+
+// GetSystemInfo 获取系统基本信息
+func GetSystemInfo() (map[string]interface{}, error) {
+ hostInfo, err := host.Info()
+ if err != nil {
+ return nil, fmt.Errorf("获取主机信息失败: %v", err)
+ }
+
+ return map[string]interface{}{
+ "os": runtime.GOOS,
+ "arch": runtime.GOARCH,
+ "hostname": hostInfo.Hostname,
+ "platform": hostInfo.Platform,
+ "platform_ver": hostInfo.PlatformVersion,
+ "kernel_ver": hostInfo.KernelVersion,
+ "uptime": hostInfo.Uptime,
+ "boot_time": hostInfo.BootTime,
+ "cpu_count": runtime.NumCPU(),
+ }, nil
+}
+
+// GetCPUInfo 获取 CPU 信息
+func GetCPUInfo() (map[string]interface{}, error) {
+ cpuCount, err := cpu.Counts(true)
+ if err != nil {
+ return nil, fmt.Errorf("获取 CPU 核心数失败: %v", err)
+ }
+
+ cpuPercent, err := cpu.Percent(0, false)
+ if err != nil {
+ return nil, fmt.Errorf("获取 CPU 使用率失败: %v", err)
+ }
+
+ cpuInfo, err := cpu.Info()
+ if err != nil {
+ return nil, fmt.Errorf("获取 CPU 详细信息失败: %v", err)
+ }
+
+ cpuModel := "Unknown"
+ if len(cpuInfo) > 0 {
+ cpuModel = cpuInfo[0].ModelName
+ }
+
+ usage := 0.0
+ if len(cpuPercent) > 0 {
+ usage = cpuPercent[0]
+ }
+
+ return map[string]interface{}{
+ "cores": cpuCount,
+ "model": cpuModel,
+ "usage": fmt.Sprintf("%.2f%%", usage),
+ "usage_raw": usage,
+ }, nil
+}
+
+// GetMemoryInfo 获取内存信息
+func GetMemoryInfo() (map[string]interface{}, error) {
+ memInfo, err := mem.VirtualMemory()
+ if err != nil {
+ return nil, fmt.Errorf("获取内存信息失败: %v", err)
+ }
+
+ formatBytes := func(bytes uint64) string {
+ const unit = 1024
+ if bytes < unit {
+ return fmt.Sprintf("%d B", bytes)
+ }
+ div, exp := int64(unit), 0
+ for n := bytes / unit; n >= unit; n /= unit {
+ div *= unit
+ exp++
+ }
+ return fmt.Sprintf("%.2f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
+ }
+
+ return map[string]interface{}{
+ "total": memInfo.Total,
+ "used": memInfo.Used,
+ "free": memInfo.Free,
+ "available": memInfo.Available,
+ "usage": fmt.Sprintf("%.2f%%", memInfo.UsedPercent),
+ "usage_raw": memInfo.UsedPercent,
+ "total_str": formatBytes(memInfo.Total),
+ "used_str": formatBytes(memInfo.Used),
+ "free_str": formatBytes(memInfo.Free),
+ "available_str": formatBytes(memInfo.Available),
+ }, nil
+}
+
+// GetDiskInfo 获取磁盘信息
+func GetDiskInfo() ([]map[string]interface{}, error) {
+ partitions, err := disk.Partitions(false)
+ if err != nil {
+ return nil, fmt.Errorf("获取磁盘分区失败: %v", err)
+ }
+
+ var result []map[string]interface{}
+ formatBytes := func(bytes uint64) string {
+ const unit = 1024
+ if bytes < unit {
+ return fmt.Sprintf("%d B", bytes)
+ }
+ div, exp := int64(unit), 0
+ for n := bytes / unit; n >= unit; n /= unit {
+ div *= unit
+ exp++
+ }
+ return fmt.Sprintf("%.2f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
+ }
+
+ for _, partition := range partitions {
+ usage, err := disk.Usage(partition.Mountpoint)
+ if err != nil {
+ continue
+ }
+
+ result = append(result, map[string]interface{}{
+ "device": partition.Device,
+ "mountpoint": partition.Mountpoint,
+ "fstype": partition.Fstype,
+ "total": usage.Total,
+ "used": usage.Used,
+ "free": usage.Free,
+ "usage": fmt.Sprintf("%.2f%%", usage.UsedPercent),
+ "usage_raw": usage.UsedPercent,
+ "total_str": formatBytes(usage.Total),
+ "used_str": formatBytes(usage.Used),
+ "free_str": formatBytes(usage.Free),
+ })
+ }
+
+ return result, nil
+}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..6c21de2
--- /dev/null
+++ b/main.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "embed"
+
+ "github.com/wailsapp/wails/v2"
+ "github.com/wailsapp/wails/v2/pkg/options"
+ "github.com/wailsapp/wails/v2/pkg/options/assetserver"
+)
+
+//go:embed all:web/dist
+var assets embed.FS
+
+func main() {
+ // 创建应用实例
+ app := NewApp()
+
+ // 创建应用配置
+ err := wails.Run(&options.App{
+ Title: "Go Desk",
+ Width: 1200,
+ Height: 800,
+ AssetServer: &assetserver.Options{
+ Assets: assets,
+ },
+ BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 1},
+ OnStartup: app.startup,
+ Bind: []interface{}{
+ app,
+ },
+ })
+
+ if err != nil {
+ println("Error:", err.Error())
+ }
+}
diff --git a/wails.json b/wails.json
new file mode 100644
index 0000000..7d99b53
--- /dev/null
+++ b/wails.json
@@ -0,0 +1,8 @@
+{
+ "name": "go-desk",
+ "outputfilename": "go-desk",
+ "frontend:dir": "web",
+ "frontend:install": "npm install",
+ "frontend:build": "npm run build",
+ "wailsjsdir": "./web/src/wailsjs"
+}
diff --git a/web/index.html b/web/index.html
new file mode 100644
index 0000000..1942efb
--- /dev/null
+++ b/web/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+ Go Desk
+
+
+
+
+
+
+
diff --git a/web/package-lock.json b/web/package-lock.json
new file mode 100644
index 0000000..79c31fc
--- /dev/null
+++ b/web/package-lock.json
@@ -0,0 +1,528 @@
+{
+ "name": "go-desk-web",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "go-desk-web",
+ "version": "1.0.0",
+ "dependencies": {
+ "@arco-design/web-vue": "^2.54.0",
+ "vue": "^3.4.0"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^5.0.0",
+ "vite": "^5.0.0"
+ }
+ },
+ "node_modules/@arco-design/color": {
+ "version": "0.4.0",
+ "license": "MIT",
+ "dependencies": {
+ "color": "^3.1.3"
+ }
+ },
+ "node_modules/@arco-design/web-vue": {
+ "version": "2.57.0",
+ "license": "MIT",
+ "dependencies": {
+ "@arco-design/color": "^0.4.0",
+ "b-tween": "^0.3.3",
+ "b-validate": "^1.5.3",
+ "compute-scroll-into-view": "^1.0.20",
+ "dayjs": "^1.11.13",
+ "number-precision": "^1.6.0",
+ "resize-observer-polyfill": "^1.5.1",
+ "scroll-into-view-if-needed": "^2.2.31",
+ "vue": "^3.1.0"
+ },
+ "peerDependencies": {
+ "vue": "^3.1.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.28.5",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.5",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.5"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.5",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.21.5",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.54.0",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.54.0",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "5.2.4",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0 || ^6.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.5.26",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.5",
+ "@vue/shared": "3.5.26",
+ "entities": "^7.0.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.5.26",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-core": "3.5.26",
+ "@vue/shared": "3.5.26"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.5.26",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.5",
+ "@vue/compiler-core": "3.5.26",
+ "@vue/compiler-dom": "3.5.26",
+ "@vue/compiler-ssr": "3.5.26",
+ "@vue/shared": "3.5.26",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.21",
+ "postcss": "^8.5.6",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.5.26",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.26",
+ "@vue/shared": "3.5.26"
+ }
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.5.26",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/shared": "3.5.26"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.5.26",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.26",
+ "@vue/shared": "3.5.26"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.5.26",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.26",
+ "@vue/runtime-core": "3.5.26",
+ "@vue/shared": "3.5.26",
+ "csstype": "^3.2.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.5.26",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.5.26",
+ "@vue/shared": "3.5.26"
+ },
+ "peerDependencies": {
+ "vue": "3.5.26"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.5.26",
+ "license": "MIT"
+ },
+ "node_modules/b-tween": {
+ "version": "0.3.3",
+ "license": "MIT"
+ },
+ "node_modules/b-validate": {
+ "version": "1.5.3",
+ "license": "MIT"
+ },
+ "node_modules/color": {
+ "version": "3.2.1",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "license": "MIT"
+ },
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/compute-scroll-into-view": {
+ "version": "1.0.20",
+ "license": "MIT"
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "license": "MIT"
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.19",
+ "license": "MIT"
+ },
+ "node_modules/entities": {
+ "version": "7.0.0",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.21.5",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "license": "MIT"
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.3.4",
+ "license": "MIT"
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/number-precision": {
+ "version": "1.6.0",
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "license": "ISC"
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/resize-observer-polyfill": {
+ "version": "1.5.1",
+ "license": "MIT"
+ },
+ "node_modules/rollup": {
+ "version": "4.54.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.54.0",
+ "@rollup/rollup-android-arm64": "4.54.0",
+ "@rollup/rollup-darwin-arm64": "4.54.0",
+ "@rollup/rollup-darwin-x64": "4.54.0",
+ "@rollup/rollup-freebsd-arm64": "4.54.0",
+ "@rollup/rollup-freebsd-x64": "4.54.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.54.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.54.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.54.0",
+ "@rollup/rollup-linux-arm64-musl": "4.54.0",
+ "@rollup/rollup-linux-loong64-gnu": "4.54.0",
+ "@rollup/rollup-linux-ppc64-gnu": "4.54.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.54.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.54.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.54.0",
+ "@rollup/rollup-linux-x64-gnu": "4.54.0",
+ "@rollup/rollup-linux-x64-musl": "4.54.0",
+ "@rollup/rollup-openharmony-arm64": "4.54.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.54.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.54.0",
+ "@rollup/rollup-win32-x64-gnu": "4.54.0",
+ "@rollup/rollup-win32-x64-msvc": "4.54.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/scroll-into-view-if-needed": {
+ "version": "2.2.31",
+ "license": "MIT",
+ "dependencies": {
+ "compute-scroll-into-view": "^1.0.20"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.4",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "5.4.21",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue": {
+ "version": "3.5.26",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.26",
+ "@vue/compiler-sfc": "3.5.26",
+ "@vue/runtime-dom": "3.5.26",
+ "@vue/server-renderer": "3.5.26",
+ "@vue/shared": "3.5.26"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/web/package.json b/web/package.json
new file mode 100644
index 0000000..35ecef5
--- /dev/null
+++ b/web/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "go-desk-web",
+ "version": "1.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "vue": "^3.4.0",
+ "@arco-design/web-vue": "^2.54.0"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^5.0.0",
+ "vite": "^5.0.0"
+ }
+}
+
diff --git a/web/package.json.md5 b/web/package.json.md5
new file mode 100644
index 0000000..8c1f360
--- /dev/null
+++ b/web/package.json.md5
@@ -0,0 +1 @@
+0e83a53f44aeb269f56998d3dfad9991
\ No newline at end of file
diff --git a/web/src/App.vue b/web/src/App.vue
new file mode 100644
index 0000000..df5871e
--- /dev/null
+++ b/web/src/App.vue
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 全部
+ 正常
+ 停用
+ 已删除
+
+
+
+
+
+
+
+
+ 查询
+
+
+
+
+
+ 重置
+
+
+
+
+
+
+
+
+
+
+ 正常
+ 停用
+ 已删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/src/components/DeviceTest.vue b/web/src/components/DeviceTest.vue
new file mode 100644
index 0000000..c36e514
--- /dev/null
+++ b/web/src/components/DeviceTest.vue
@@ -0,0 +1,306 @@
+
+
+
+
+
+ 刷新系统信息
+
+
+
+
+
核心数: {{ cpuInfo.cores }}
+
型号: {{ cpuInfo.model }}
+
使用率: {{ cpuInfo.usage }}
+
+ 加载中...
+
+
+
+
+
+
总内存: {{ memoryInfo.total_str }}
+
已用: {{ memoryInfo.used_str }}
+
可用: {{ memoryInfo.available_str }}
+
使用率: {{ memoryInfo.usage }}
+
+ 加载中...
+
+
+
+
+
+
操作系统: {{ systemInfo.os }}
+
架构: {{ systemInfo.arch }}
+
主机名: {{ systemInfo.hostname }}
+
平台: {{ systemInfo.platform }}
+
+ 加载中...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 浏览
+ 列出目录
+
+
+
+
+
+
+
+
+
+
+ {{ item.is_dir ? '📁' : '📄' }}
+ {{ item.name }}
+
+
+
+ 大小: {{ formatBytes(item.size) }}
+ 修改时间: {{ item.mod_time }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 读取文件
+ 写入文件
+ 删除
+
+
+
+
+
+
+
+
+
+
+ 加载环境变量
+
+
+
+
+
+
+
+
diff --git a/web/src/main.js b/web/src/main.js
new file mode 100644
index 0000000..e90cd9c
--- /dev/null
+++ b/web/src/main.js
@@ -0,0 +1,10 @@
+import { createApp } from 'vue'
+import ArcoVue from '@arco-design/web-vue'
+import '@arco-design/web-vue/dist/arco.css'
+import './style.css'
+import App from './App.vue'
+
+const app = createApp(App)
+app.use(ArcoVue)
+app.mount('#app')
+
diff --git a/web/src/style.css b/web/src/style.css
new file mode 100644
index 0000000..70bc1c8
--- /dev/null
+++ b/web/src/style.css
@@ -0,0 +1,17 @@
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+#app {
+ width: 100%;
+ height: 100vh;
+}
+
diff --git a/web/vite.config.js b/web/vite.config.js
new file mode 100644
index 0000000..15ff6a3
--- /dev/null
+++ b/web/vite.config.js
@@ -0,0 +1,11 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+export default defineConfig({
+ plugins: [vue()],
+ build: {
+ outDir: 'dist',
+ emptyOutDir: true
+ }
+})
+