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 @@ + + + + + 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 + } +}) +