# 基于 Wails 的桌面程序搭建

## 技术栈

- Go v1.25.4
- Wails v2
- Arco Design Vue
- Vue 3

## 环境准备

### 1. 安装 Wails CLI

```bash
go install github.com/wailsapp/wails/v2/cmd/wails@latest
```

### 2. 验证安装

```bash
wails version
```

## 项目初始化

### 1. 创建项目

```bash
wails init -n go-desk -t vanilla
```

### 2. 项目结构

```
go-desk/
├── app.go                  # 应用逻辑，暴露给前端的方法
├── main.go                 # 程序入口，初始化 Wails 应用
├── wails.json              # Wails 配置文件
├── go.mod                  # Go 模块依赖
├── go.sum                  # Go 依赖校验
├── frontend/                    # 前端代码目录
│   ├── package.json        # 前端依赖配置
│   ├── package-lock.json   # 依赖锁定文件
│   ├── vite.config.js      # Vite 构建配置
│   ├── index.html          # HTML 入口文件
│   ├── src/
│   │   ├── main.js         # Vue 应用入口
│   │   ├── App.vue         # 根组件
│   │   └── style.css       # 全局样式
│   └── dist/               # 构建产物（构建后生成）
│       ├── index.html
│       ├── assets/
│       └── ...
├── build/                  # 构建资源目录
│   ├── appicon.png         # 应用图标
│   └── windows/            # Windows 构建资源（可选）
│       └── icon.ico
└── build/bin/              # 编译后的可执行文件（构建后生成）
    └── go-desk.exe         # Windows 可执行文件
```

**目录说明：**
- `app.go`: 定义应用结构体和方法，供前端调用
- `main.go`: 程序入口，配置窗口、资源等
- `frontend/`: 前端 Vue 项目，使用 Vite 构建
- `frontend/dist/`: 前端构建产物，会被嵌入到 Go 二进制文件
- `build/`: 应用图标等构建资源

## 配置调整

### 1. 配置 Wails 使用 web 目录

如果使用 `web` 作为前端目录（而非默认的 `frontend`），需要在 `wails.json` 中配置：

```json
{
  "frontend": {
    "dir": "web"
  }
}
```

### 2. 安装 Arco Design Vue

```bash
cd web
npm install --save @arco-design/web-vue
```

### 3. 修改 `frontend/src/main.js`

```javascript
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')
```

### 4. 修改 `frontend/src/App.vue`

```vue
<template>
  <a-layout class="layout">
    <a-layout-header>
      <div class="header-content">
        <h2>Go Desk Demo</h2>
      </div>
    </a-layout-header>
    <a-layout-content class="content">
      <a-card>
        <template #title>欢迎</template>
        <p>这是一个基于 Wails + Arco-Vue 的最小 Demo</p>
        <a-button type="primary" @click="handleClick">点击测试</a-button>
        <p v-if="message">{{ message }}</p>
      </a-card>
    </a-layout-content>
  </a-layout>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      message: ''
    }
  },
  methods: {
    async handleClick() {
      // 调用 Go 后端方法
      if (window.go && window.go.main && window.go.main.Greet) {
        try {
          const result = await window.go.main.Greet('World')
          this.message = result
        } catch (error) {
          this.message = '调用失败: ' + error.message
        }
      } else {
        this.message = 'Go 后端未就绪'
      }
    }
  }
}
</script>

<style>
.layout {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.header-content {
  display: flex;
  align-items: center;
  height: 100%;
  padding: 0 20px;
  color: var(--color-text-1);
}

.content {
  padding: 20px;
  flex: 1;
  overflow: auto;
}
</style>
```

### 5. 修改 `app.go` - Go 后端

```go
package main

import (
	"context"
	"fmt"
)

// App struct
type App struct {
	ctx context.Context
}

// NewApp creates a new App application struct
func NewApp() *App {
	return &App{}
}

// startup is called when the app starts. The context is saved
// so we can call the runtime methods
func (a *App) startup(ctx context.Context) {
	a.ctx = ctx
}

// Greet returns a greeting for the given name
func (a *App) Greet(name string) string {
	return fmt.Sprintf("Hello %s, It's show time!", name)
}
```

### 6. 修改 `main.go`

```go
package main

import (
	"context"
	"embed"

	"github.com/wailsapp/wails/v2"
	"github.com/wailsapp/wails/v2/pkg/options"
	"github.com/wailsapp/wails/v2/pkg/options/assetserver"
)

//go:embed all:frontend/dist
var assets embed.FS

func main() {
	// Create an instance of the app structure
	app := NewApp()

	// Create application with options
	err := wails.Run(&options.App{
		Title:  "Go Desk",
		Width:  1024,
		Height: 768,
		AssetServer: &assetserver.Options{
			Assets: assets,
		},
		BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
		OnStartup:        app.startup,
	})

	if err != nil {
		println("Error:", err.Error())
	}
}
```

## 开发运行

### 1. 开发模式

```bash
# 终端1：启动前端开发服务器
cd web
npm run dev

# 终端2：启动 Wails 开发模式
wails dev
```

### 2. 构建前端

```bash
cd web
npm run build
```

### 3. 构建应用

```bash
# 构建当前平台
wails build

# 构建 Windows
wails build -platform windows/amd64

# 构建 macOS
wails build -platform darwin/amd64

# 构建 Linux
wails build -platform linux/amd64
```

## 注意事项

1. **前端构建**：每次修改前端代码后需要重新构建 `npm run build`，Wails 会使用 `frontend/dist` 目录
2. **Go 方法暴露**：在 `app.go` 中定义的方法会自动暴露给前端，通过 `window.go.main.MethodName` 调用
3. **热重载**：开发模式下，Go 代码修改需要重启 `wails dev`，前端代码修改需要重新构建
4. **资源嵌入**：使用 `//go:embed` 将前端构建产物嵌入到 Go 二进制文件中

## 参考

- [Wails 官方文档](https://wails.io/docs/)
- [Arco Design Vue](https://arco.design/vue/docs/start)

