6.8 管理端前端开发
前端开发(admin-webui)
dwz-server 的管理后台是一个独立的前端仓库 admin-webui,基于 Vben Admin v5 构建,最终产物会被嵌入到 Go 后端的二进制中(通过 //go:embed static/admin/)。
技术栈
| 类别 | 选型 |
|---|---|
| 框架 | Vue 3.5 + TypeScript 5.8 |
| 构建 | Vite 7 + Turbo + pnpm workspace |
| UI 库 | Ant Design Vue 4.2 |
| 状态管理 | Pinia 3(含 persistedstate 插件) |
| 路由 | Vue Router 4(hash 模式) |
| HTTP | @vben/request(axios 封装) |
| 表单校验 | Vee-validate + Zod |
| 样式 | Tailwind CSS 3 |
| 包管理 | 必须使用 pnpm 10+ |
| Node | 22.1.0+ |
仓库地址
- CNB:https://cnb.cool/mliev/open/dwz-admin-webui
- Gitee:https://gitee.com/muleiwu/dwz-admin-webui
- GitHub:https://github.com/muleiwu/dwz-admin-webui
建议把 admin-webui 与 dwz-server 克隆到同一父目录,便于打包脚本找到前端产物:
workspace/
├── dwz-server/ # Go 后端
└── admin-webui/ # Vue 前端Monorepo 结构
admin-webui 是 Turbo + pnpm workspace 组织的 monorepo:
admin-webui/
├── apps/
│ └── web-antd/ # 主应用:dwz 管理后台(Ant Design Vue 版本)
├── packages/
│ ├── @core/ # 共享 Vue 组件、设计系统、基础工具
│ ├── effects/ # icons、locales、stores 等副作用模块
│ └── business/ # 业务组件
├── internal/ # 构建配置包:@vben/vite-config、@vben/tsconfig 等
├── scripts/ # 部署与工具脚本
├── docs/ # 文档(含 API.md)
├── pnpm-workspace.yaml # workspace 声明 + catalog 版本目录
├── turbo.json # Turbo 任务流水线
└── package.json只有
apps/web-antd一个应用,其余 packages 都是被它引用的内部库。
开发命令
所有命令在 admin-webui/ 根目录执行:
| 命令 | 说明 |
|---|---|
pnpm install |
安装依赖(首次必跑) |
pnpm dev:antd |
启动开发服务器(默认 http://localhost:5666) |
pnpm build:antd |
打包生产版本到 apps/web-antd/dist/ |
pnpm build:analyze |
带包体积分析的构建 |
pnpm lint |
ESLint + Prettier + StyleLint |
pnpm format |
自动格式化 |
pnpm typecheck |
全量 TypeScript 检查(vue-tsc) |
pnpm test:unit |
Vitest 单元测试 |
pnpm clean |
清理 node_modules 与产物 |
首次启动
git clone https://cnb.cool/mliev/open/dwz-admin-webui.git admin-webui
cd admin-webui
# 启用 pnpm(如未安装)
corepack enable
corepack prepare pnpm@latest --activate
pnpm install
pnpm dev:antd浏览器访问 http://localhost:5666/admin/,开发服务器会自动把 /api/* 代理到后端。
后端对接
开发期代理
Vite 配置在 apps/web-antd/vite.config.mts 内设置了 dev 代理:默认把 /api/* 转发到后端。请先启动 Go 后端 (go run main.go),再启动前端 dev server,否则 API 调用会失败。
若后端不是默认 8080 端口,可通过环境变量覆盖:
VITE_GLOB_API_URL=http://127.0.0.1:9090 pnpm dev:antd生产环境 API 地址
生产环境通常把前端产物跟后端同源部署(由 Go 后端直接托管 /admin/),此时 VITE_GLOB_API_URL 留空,前端使用相对路径 /api/v1/... 请求本域。
环境变量(Vite)
位于 apps/web-antd/ 下:
| 文件 | 用途 |
|---|---|
.env |
通用默认值 |
.env.development |
开发覆盖:API 指向本地后端、devtools 开启 |
.env.production |
生产覆盖:API 留空、hash 路由 |
常用变量:
VITE_BASE— 应用基路径,固定/admin/VITE_GLOB_API_URL— 后端 API 根地址VITE_ROUTER_HISTORY— 路由模式,hash方便部署到任意路径VITE_APP_NAMESPACE/VITE_APP_VERSION— 用于 store 隔离
Vite 环境变量仅在 构建时 注入,不支持运行时替换。若需要根据部署环境动态切换 API 地址,建议走反向代理同源 + 相对路径方案。
关键目录:apps/web-antd/src
| 目录 | 职责 |
|---|---|
api/ |
API 客户端层,按业务模块拆分的 TypeScript 接口 |
api/core/auth.ts |
登录、刷新 Token、登出 |
api/shortlink.ts、ab-test.ts、user-management.ts |
业务接口 |
api/request.ts |
axios 封装:鉴权拦截器、统一错误处理、Token 刷新 |
store/ |
Pinia stores(auth.ts 管理登录态和用户信息) |
router/routes/modules/ |
路由模块:dashboard / shortlink / system |
router/access.ts |
基于权限的路由访问控制 |
router/guard.ts |
路由守卫:登录校验、权限判定 |
views/ |
页面组件,按业务分组(dashboard / shortlink / system / profile) |
components/ |
可复用 UI 组件(如 QRCodeGenerator) |
layouts/ |
应用外壳(侧边栏、顶栏、底部) |
locales/langs/ |
i18n 翻译(中文 / 英文) |
adapter/ |
UI 库适配层,统一注册组件 |
types/ |
TypeScript 类型定义 |
API 调用规范
所有后端请求必须通过 src/api/*.ts 封装的函数发起,不要在 Vue 组件里直接调用 axios。
调用示例
import { loginApi, getShortLinkList } from '#/api';
// 登录
const { token, user } = await loginApi({ username, password });
// 分页查询
const { list, total } = await getShortLinkList({
page: 1,
page_size: 10,
});响应格式
统一期望后端返回:
{ "code": 0, "data": { ... }, "message": "success" }code !== 0 时拦截器会自动弹出全局错误提示,业务层只需处理 data。
新增接口
- 在
src/api/下新建或扩展对应模块文件(如src/api/tag.ts) - 定义请求参数与响应类型
- 导出函数:
import { requestClient } from '#/api/request';
export interface CreateTagParams {
name: string;
color?: string;
}
export function createTagApi(params: CreateTagParams) {
return requestClient.post<{ id: number }>('/api/v1/tags', params);
}- 在页面中直接 import 使用
登录与鉴权流程
登录态由 Pinia auth store(src/store/auth.ts)管理:
- 用户提交表单 →
loginApi()返回token+ 用户信息 accessStore.accessToken存储 Token,自动持久化(localStorage)- 后续所有请求由拦截器自动注入
Authorization: Bearer <token> - 收到 401 时尝试调用刷新接口
- 收到 429(限频锁定)时提示剩余次数并停留登录页
- 登出清空所有 store,跳转登录页
路由守卫 src/router/guard.ts 会在进入受保护页面前检查登录态与权限。
构建产物与后端集成
构建输出
apps/web-antd/dist/Vite 配置 base: '/admin/',所有静态资源引用路径都是 /admin/*。
嵌入后端二进制
后端 main.go 通过 //go:embed static/admin/** 把前端产物打进 Go 二进制。因此每次前端改完后,需要把 dist/ 的内容复制到后端的 static/admin/ 再构建后端:
# 1. 构建前端
cd admin-webui
pnpm install
pnpm build:antd
# 2. 拷贝到后端
cd ..
rm -rf dwz-server/static/admin
mkdir -p dwz-server/static/admin
cp -r admin-webui/apps/web-antd/dist/* dwz-server/static/admin/
# 3. 构建后端
cd dwz-server
CGO_ENABLED=0 go build -ldflags="-s -w" -o dwz-server main.goDocker 部署
admin-webui 自带 Dockerfile,独立发布前端镜像(Nginx 托管):
- 第一阶段:Node 22 镜像跑
pnpm build:antd - 第二阶段:把
dist/拷到 nginx 容器的/usr/share/nginx/html/admin - 监听 80 端口
但 dwz-server 推荐的部署模式 是把前端嵌入后端二进制,不单独跑前端容器;nginx 仅在需要 CDN/多实例缓存时才单独部署。
常见问题
Q1: 启动 dev server 报 "ERR_PNPM_UNSUPPORTED_ENGINE"
Node 版本低于 22.1.0。用 nvm use 22 或 fnm use 22 切换。
Q2: 接口全部 401 / CORS 报错
- 确认后端
go run main.go已启动 - 确认已在后端登录获取 Token(或前端调用
loginApi) - 确认
VITE_GLOB_API_URL指向正确后端地址 - 开发期若走跨域,请检查后端
cors配置是否允许http://localhost:5666
Q3: 页面空白,控制台报 "Failed to fetch dynamically imported module"
一般是构建产物与浏览器缓存不一致。清浏览器缓存或改配 base 后重新 pnpm build:antd。
Q4: 改了后端路由前端没反应
前端的 API 封装在 src/api/,需要手工同步修改;TypeScript 类型也要更新,否则编辑器会报错。
Q5: 想本地跑一次完整的"打包 + 嵌入后端"流程
参考上面「嵌入后端二进制」的三步脚本;也可以直接参考仓库根目录 dwz-server/docs/manual-build.md。
文档与参考
- Vben Admin 官方文档:https://doc.vben.pro/ — 组件、布局、权限、主题等通用用法
- Ant Design Vue:https://www.antdv.com/ — UI 组件 API
- API 文档:
admin-webui/docs/API.md(OpenAPI 风格的后端接口速查) - API 客户端说明:
admin-webui/apps/web-antd/src/api/README.md