前端总览
前端总览
业务用途
本文是前端架构的总纲,帮助你快速建立对整个前端工程的全局认知:用了哪些技术、Vite 如何配置自动导入、目录如何组织、本地如何启动、前端与后端如何通过代理通信。后续每一章都在此基础上展开。
涉及文件
frontend/vite.config.ts-- Vite 构建配置(插件、别名、代理)frontend/package.json-- 依赖与脚本frontend/src/main.ts-- 应用入口(注册插件、挂载应用)frontend/src/App.vue-- 根组件frontend/tsconfig.app.json/frontend/tsconfig.json-- TypeScript 配置frontend/tailwind.config.js/frontend/postcss.config.js-- 样式配置
实现机制
技术栈
前端基于 Vue 3.5 + TypeScript + Vite 8,关键依赖见 frontend/package.json:
{
"dependencies": {
"vue": "^3.5.32",
"vue-router": "^4.6.4",
"pinia": "^3.0.4",
"element-plus": "^2.13.7",
"@element-plus/icons-vue": "^2.3.2",
"axios": "^1.16.0",
"echarts": "^6.0.0",
"bpmn-js": "^17.11.1",
"@form-create/designer": "^3.4.0",
"@form-create/element-ui": "^3.3.0",
"vuedraggable": "^4.1.0",
"sortablejs": "^1.15.7",
"@vueuse/core": "^14.3.0",
"@iconify/vue": "^5.0.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.6",
"vite": "^8.0.10",
"typescript": "~6.0.2",
"tailwindcss": "^3.4.19",
"sass-embedded": "^1.99.0"
}
}为什么选这套技术栈
- Vue 3.5 +
<script setup>:组合式 API 让设计器这类复杂组件的状态逻辑可组合、可复用。 - Vite 8:开发期秒级冷启动 + HMR,生产期 Rollup 打包。
- Element Plus 2.13:企业级后台组件库,覆盖表格、表单、弹窗、抽屉等高频场景。
- Pinia 3:轻量状态管理,配合 localStorage 做持久化。
- @form-create:表单设计器 + 表单渲染引擎,是低代码表单能力的基石。
- bpmn-js:业界标准 BPMN 2.0 建模器,用于专业流程设计。
Vite 配置:自动导入与组件自动注册
frontend/vite.config.ts 是前端构建的核心配置:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { resolve } from 'path'
export default defineConfig({
plugins: [
vue(),
// 1. 自动导入 API:ref / reactive / computed / watch / useRoute / useRouter / defineStore 等
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
resolvers: [ElementPlusResolver()],
dts: 'src/auto-imports.d.ts'
}),
// 2. 自动注册组件:<el-button> / <ElButton> 无需手动 import
Components({
resolvers: [ElementPlusResolver()],
dts: 'src/components.d.ts'
})
],
resolve: {
alias: { '@': resolve(__dirname, 'src') }
},
server: {
host: '0.0.0.0',
port: 3000,
proxy: {
'/api': {
target: 'http://127.0.0.1:52856',
changeOrigin: true,
rewrite: (path) => path
}
}
}
})unplugin-auto-import(API 自动导入)
AutoImport 插件扫描代码中的 ref、reactive、computed、watch、onMounted、useRoute、useRouter、defineStore 等符号,自动在编译期注入 import 语句。因此你在 .vue / .ts 文件里可以直接使用这些 API 而无需手动导入:
<script setup lang="ts">
// 无需 import { ref, onMounted } from 'vue'
const count = ref(0)
onMounted(() => console.log('mounted'))
</script>插件会生成类型声明文件 frontend/src/auto-imports.d.ts,让 TypeScript 识别这些全局符号。该文件由插件自动维护,不要手动编辑,应加入 .gitignore 或随插件版本更新。
注意
自动导入只覆盖 vue、vue-router、pinia 三个预设以及 Element Plus 的 API。从 @/utils/request、@/store/user、@/api/xxx 等业务模块导入的内容仍需手动 import。
unplugin-vue-components(组件自动注册)
Components 插件配合 ElementPlusResolver,让你在模板中直接使用 <el-button>、<el-table>、<el-form> 等组件而无需 import 和 app.component() 注册。插件按需引入 Element Plus 的组件样式,实现 Tree-shaking。
生成的 frontend/src/components.d.ts 声明了这些组件类型,同样由插件自动维护。
路径别名
resolve: {
alias: { '@': resolve(__dirname, 'src') }
}@ 指向 src 目录,例如 @/utils/request 对应 src/utils/request.ts,@/store/user 对应 src/store/user.ts。这在 TypeScript 中由 tsconfig.app.json 的 paths 配置同步映射,保证类型检查正常。
开发服务器与代理
server: {
host: '0.0.0.0', // 监听所有网卡,支持局域网 IP 访问
port: 3000, // 前端端口
proxy: {
'/api': {
target: 'http://127.0.0.1:52856', // 后端端口
changeOrigin: true,
rewrite: (path) => path // 不重写路径,/api 前缀原样转发
}
}
}为什么用 127.0.0.1 而不是 localhost
配置注释明确说明:某些 Node 版本会把 localhost 解析成 IPv6 的 ::1,如果后端只监听 IPv4,代理会连接失败。使用 127.0.0.1 强制走 IPv4,避免这个坑。
代理的工作流程:
- 前端 axios 的
baseURL设为/api(见 )。 - 浏览器发出的请求形如
http://localhost:3000/api/system/user/list。 - Vite dev server 匹配
/api前缀,将其原样转发到http://127.0.0.1:52856/api/system/user/list。 - 后端 Controller 的路径本身就带
/api前缀,因此changeOrigin+ 不重写路径的组合让前后端路径自然对齐。
应用入口
frontend/src/main.ts 负责创建并挂载应用:
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { Icon } from '@iconify/vue'
import { createPinia } from 'pinia'
import formCreate from '@form-create/element-ui'
import FcDesigner from '@form-create/designer'
import router from './router'
import { setupPermissionDirective } from './directives/permission'
import './styles/index.scss'
import App from './App.vue'
const app = createApp(App)
// 注册所有 Element Plus 图标为全局组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
// 注册 Iconify 的 Icon 组件
app.component('Icon', Icon)
app.use(ElementPlus, { locale: zhCn }) // Element Plus + 中文语言包
app.use(createPinia()) // Pinia 状态管理
app.use(router) // Vue Router
app.use(formCreate) // @form-create 表单渲染引擎
app.use(FcDesigner) // @form-create 表单设计器
setupPermissionDirective(app) // 注册 v-permission / v-role 指令
app.mount('#app')v-permission 与 v-role 指令
src/directives/permission.ts 注册了两个自定义指令,用于按钮级权限控制:
<!-- 只有拥有 system:user:add 权限才显示 -->
<el-button v-permission="'system:user:add'">新增</el-button>
<!-- 拥有 admin 或 manager 角色之一即显示 -->
<el-button v-role="['admin', 'manager']">删除</el-button>指令内部调用 userStore.hasPermission(value) / userStore.hasRole(value),无权限时直接从 DOM 移除元素。
目录组织
frontend/src/
├── api/ # 接口模块(按业务拆分)
│ ├── bpm/ # 流程相关接口(model / task / definition / form / ...)
│ ├── erp/ # ERP 业务接口
│ ├── hr/ # 人事业务接口
│ ├── system/ # 系统管理接口(role / dept / post / user / ...)
│ ├── auth.ts # 登录 / 登出 / 用户信息
│ ├── dict.ts # 字典接口
│ └── ...
├── assets/ # 静态资源
├── components/ # 公共组件
│ ├── BpmnDesigner/ # bpmn-js 流程图设计器
│ ├── FormComponents/ # 表单渲染组件库(签名 / 定位 / 富文本 / ...)
│ ├── FormCreate/ # @form-create 表单设计器封装
│ ├── SimpleProcessDesignerV2/ # 钉钉式简易流程设计器
│ ├── ProTable.vue # 通用表格
│ ├── ProCard.vue # 通用卡片
│ ├── QueryForm.vue # 查询表单
│ ├── DictSelect.vue # 字典下拉
│ ├── StatusTag.vue # 状态标签
│ ├── ActionButton.vue # 操作按钮组
│ ├── EmptyState.vue # 空状态
│ └── TenantUserSelect.vue # 租户用户选择
├── composables/ # 组合式函数
├── constants/ # 常量
├── directives/ # 自定义指令(permission)
├── layout/ # 主布局(侧边栏 + 顶栏 + 菜单)
├── router/ # 路由(index.ts 单文件)
├── store/ # Pinia 状态(user.ts)
├── styles/ # 全局样式
├── types/ # TypeScript 类型定义
├── utils/ # 工具函数(request.ts / dict.ts / tree.ts / ...)
└── views/ # 页面视图
├── ai/ # AI 助手
├── application/ # 应用管理 / 应用构建器
├── bpm/ # 流程中心(模型 / 定义 / 待办 / 审批)
├── dashboard/ # 首页 / 仪表盘
├── database/ # 表设计器 / 数据管理 / 数据源
├── designer/ # 各类设计器(表单 / 列表 / 页面 / 流程 / 报表 / 打印)
├── erp/ # ERP 业务(供应商 / 客户 / 采购 / 销售 / 库存 / ...)
├── generator/ # 代码生成器
├── hr/ # 人事管理
├── login/ # 登录 / SSO 回调
├── runtime/ # 应用运行时(AppRuntime.vue)
├── system/ # 系统管理(用户 / 角色 / 菜单 / 部门 / 租户 / 字典 / ...)
└── template/ # 行业模板
操作步骤
本地启动
# 1. 进入前端目录
cd frontend
# 2. 安装依赖(推荐 pnpm)
pnpm install
# 3. 启动开发服务器(默认端口 3000)
pnpm dev启动后访问 http://localhost:3000,开发服务器会自动将 /api 开头的请求代理到后端 http://127.0.0.1:52856。
前置条件
- 后端服务必须已在 52856 端口启动,否则登录与所有接口都会返回网络错误。
- 若需局域网访问,
host: '0.0.0.0'已配置,可通过http://<本机IP>:3000访问。
生产构建
pnpm build # 先 vue-tsc 类型检查,再 vite build 产物到 dist/
pnpm preview # 本地预览生产产物常见问题
自动导入不生效,TypeScript 报错找不到 ref / computed
unplugin-auto-import 生成的 src/auto-imports.d.ts 是类型声明的关键。如果该文件缺失或 IDE 未加载,TS 会报 Cannot find name 'ref'。解决方法:
- 确认
vite.config.ts中AutoImport的dts: 'src/auto-imports.d.ts'配置存在。 - 重启 dev server 让插件重新生成声明文件。
- 在 IDE(VSCode / WebStorm)中确认
tsconfig.app.json的include覆盖了src/auto-imports.d.ts。
修改 vite.config.ts 后代理不生效
Vite 对 vite.config.ts 的变更需要重启 dev server(不是 HMR)。修改代理 target 或端口后,务必 Ctrl+C 停止后重新 pnpm dev。
局域网访问报 Hostname not allowed
这是 Vite 的 server.allowedHosts 安全限制。如需开放,可在 server 配置中添加 allowedHosts: true 或具体主机名(生产环境慎用)。
Element Plus 组件样式丢失
unplugin-vue-components 的 ElementPlusResolver 会自动按需引入样式。如果出现样式丢失,通常是 src/components.d.ts 过期或 main.ts 中 import 'element-plus/dist/index.css' 被误删。全量样式入口在 main.ts 顶部引入,不要删除。
下一步
- 了解路由如何按权限动态加载:
- 了解 axios 如何封装统一请求:
- 了解用户状态如何持久化:
