Add Playwright configuration and E2E specs for key production, purchasing, and warehouse flows, and update layout/login to align with the new testing setup. Made-with: Cursor
298 lines
12 KiB
Markdown
298 lines
12 KiB
Markdown
# 铭奕 ERP 前端(erp-frontend-vue)
|
||
|
||
基于 **Vue 3 + TypeScript + Vite + Element Plus** 实现的 ERP Web 前端,覆盖主数据、销售、采购、生产计划、仓储、系统管理等业务模块。
|
||
|
||
本文档用于说明项目整体架构和约定,方便后续功能迭代、Bug 修复以及测试用例编写。
|
||
|
||
---
|
||
|
||
## 1. 技术栈与关键依赖
|
||
|
||
- **框架**:Vue 3(`<script setup>` 语法)
|
||
- **语言**:TypeScript(严格类型约束,配合 `vue-tsc` 做构建时类型检查)
|
||
- **构建工具**:Vite
|
||
- **UI 组件库**:Element Plus(含图标集 `@element-plus/icons-vue`)
|
||
- **路由**:Vue Router 4
|
||
- **HTTP 客户端**:Axios(统一封装在 `src/api/request.ts`)
|
||
- **测试**:Vitest + @vue/test-utils + jsdom
|
||
|
||
主要脚本(见 `package.json`):
|
||
|
||
- `npm run dev`:启动开发服务器
|
||
- `npm run build`:先运行 `vue-tsc -b` 做类型检查,再用 Vite 打生产包
|
||
- `npm run preview`:预览生产构建
|
||
- `npm run test`:一次性运行所有 Vitest 用例
|
||
- `npm run test:watch`:watch 模式运行 Vitest
|
||
|
||
---
|
||
|
||
## 2. 目录结构概览
|
||
|
||
仅列出与前端业务开发关系最密切的部分:
|
||
|
||
- `src/main.ts`:应用入口,创建 Vue 应用,注册 Element Plus 图标,挂载路由与权限守卫
|
||
- `src/App.vue`:根组件
|
||
- `src/router/index.ts`:路由配置(按业务域划分路由树)
|
||
- `src/permission.ts`:路由前置守卫,处理登录校验、用户信息加载、白名单路由等
|
||
- `src/layout/`
|
||
- `index.vue`:主布局(侧边菜单 + 顶部导航 + 面包屑 + 内容区域)
|
||
- `src/stores/`
|
||
- `user.ts`:用户状态与权限校验(登录、退出、获取用户信息等)
|
||
- `src/api/`
|
||
- `request.ts`:Axios 实例及请求/响应拦截器
|
||
- 业务 API 模块(每个文件对应一个业务域,内部定义 TypeScript 接口与请求方法),例如:
|
||
- `auth.ts`:认证登录/获取用户信息
|
||
- `productionPlan.ts`:生产计划单
|
||
- `mbom.ts`:物料清单 / MRP
|
||
- `purchasePlan.ts`:采购计划
|
||
- `purchaseOrder.ts`:采购订单
|
||
- `salesOrder.ts`:销售订单
|
||
- `deliver.ts` / `invoice.ts` / `saleback.ts`:销售相关单据
|
||
- `masterdata/*`:物料、计量单位、车间、工作站等主数据
|
||
- `system/*`:组织架构(部门、岗位、角色、用户)
|
||
- `warehouse/*`:生产领料相关接口
|
||
- `rd/ebom.ts`:研发 BOM
|
||
- `src/views/`:按业务域划分的页面组件
|
||
- `MasterData/`:主数据
|
||
- `Sales/`:销售管理与销售报表
|
||
- `Purchasing/`:采购管理与采购报表
|
||
- `Production/`:生产计划、MBOM/MRP、采购计划、生产报表
|
||
- `Warehouse/Issue/`:生产领料单
|
||
- `RD/Ebom/`:研发 EBOM
|
||
- `System/`:用户、角色、部门、岗位
|
||
- 每个业务通常使用:
|
||
- `index.vue`:列表/查询页
|
||
- `form.vue`:单据编辑/查看页
|
||
- `src/utils/`:通用工具(如 token 存取等)
|
||
|
||
---
|
||
|
||
## 3. 运行与构建
|
||
|
||
```bash
|
||
# 安装依赖
|
||
npm install
|
||
|
||
# 开发调试
|
||
npm run dev
|
||
|
||
# 类型检查 + 构建生产包
|
||
npm run build
|
||
|
||
# 本地预览生产包
|
||
npm run preview
|
||
|
||
# 运行单元测试
|
||
npm run test
|
||
```
|
||
|
||
> 建议在提交代码前至少保证 `npm run build` 通过,以防止 TypeScript 类型错误和明显的构建问题进入主分支。
|
||
|
||
---
|
||
|
||
## 4. 前端架构设计
|
||
|
||
### 4.1 路由与布局
|
||
|
||
- 路由配置集中在 `src/router/index.ts`,采用**按业务域分组**的嵌套路由结构:
|
||
- `/sales/*`:销售管理模块
|
||
- `/purchasing/*`:采购管理模块
|
||
- `/production/*`:生产计划模块
|
||
- `/masterdata/*`:主数据维护
|
||
- `/system/*`:系统管理
|
||
- `/warehouse/*`:仓储/生产领料
|
||
- `/rd/*`:研发
|
||
- 所有业务路由均以 `Layout` 作为父路由,实现统一的侧边菜单 + 顶部导航 + 面包屑结构。
|
||
- 每个路由都带有 `meta.title`,用于:
|
||
- 页面标题(`permission.ts` 中设置 `document.title`)
|
||
- 面包屑显示
|
||
- 侧边菜单高亮匹配
|
||
|
||
### 4.2 权限与认证流程
|
||
|
||
相关文件:
|
||
|
||
- `src/stores/user.ts`:维护用户 token、基本信息、角色、权限等
|
||
- `src/utils/auth.ts`:token 的本地存储读写
|
||
- `src/api/auth.ts`:登录、获取用户信息、注销
|
||
- `src/permission.ts`:全局路由守卫
|
||
|
||
核心逻辑:
|
||
|
||
1. 路由进入前,`permission.ts` 会检查:
|
||
- 当前是否在白名单(如 `/login` 等)
|
||
- 本地是否存在 token
|
||
2. 若有 token 但 `userStore.state.userInfo.roles` 为空,则会调用 `userStore.getUserInfo()` 拉取用户信息。
|
||
3. 若认证失败或接口错误,会调用 `fedLogout` 清理本地状态,并跳转登录页。
|
||
4. 在开发模式下支持 `DEV_SKIP_AUTH`(通过 `import.meta.env` 控制),方便后端未就绪时调试页面。
|
||
|
||
### 4.3 API 封装与数据访问
|
||
|
||
统一入口:`src/api/request.ts`
|
||
|
||
- 使用 Axios 创建单例 `request`,通过请求拦截器自动处理:
|
||
- 按 URL 前缀自动拼接 `/erp`、`/mes`、`/system` 等前缀
|
||
- 附加 `Authorization: Bearer <token>` 头
|
||
- 响应拦截器统一处理:
|
||
- `code === 401`:弹出重新登录提示,清理 token 并跳转登录
|
||
- 其他非 200 code:使用 `ElMessage.error` 提示
|
||
- 成功时统一返回包裹后的 `res` 对象(通常包含 `data`、`rows`、`total` 等)
|
||
|
||
业务 API 模块模式(以 `src/api/productionPlan.ts` 为例):
|
||
|
||
- 在文件顶部定义接口类型,如 `ProductionPlan`、`PlanLine` 等。
|
||
- 导出对应的请求方法:
|
||
- `getProductionPlanList(params: PlanQuery)`
|
||
- `createProductionPlan(data: Partial<ProductionPlan>)`
|
||
- `approveProductionPlan(planId: number)` 等。
|
||
- 列表接口通常约定返回 `{ rows: T[]; total: number }` 结构,方便列表分页展示。
|
||
|
||
> **建议**:新增接口时先定义好 TypeScript 接口类型,再在页面组件中通过 `type Xxx` 引用,保持前后端字段的一致性与可维护性。
|
||
|
||
### 4.4 状态管理
|
||
|
||
当前项目使用 **轻量级的自实现 store**(并未引入 Pinia/Vuex),例如:
|
||
|
||
- `src/stores/user.ts` 使用 `reactive` 维护用户状态,并暴露:
|
||
- `loginAction` / `logoutAction` / `getUserInfo`
|
||
- `hasRole`、`hasPermission` 做按钮级权限控制
|
||
|
||
在组件中通过:
|
||
|
||
```ts
|
||
import { useUserStore } from '@/stores/user'
|
||
|
||
const userStore = useUserStore()
|
||
```
|
||
|
||
来访问和修改全局用户状态。
|
||
|
||
### 4.5 业务模块划分
|
||
|
||
按典型业务流程进行模块化:
|
||
|
||
- **主数据(MasterData)**:物料、分类、计量单位、车间/工作站等基础资料。
|
||
- **销售(Sales)**:客户、销售订单、发货通知单、开票结算单、退货通知单以及相关报表。
|
||
- **采购(Purchasing)**:供应商、采购订单、到货单、发票、退货及采购执行报表。
|
||
- **生产(Production)**:生产计划单、MBOM/MRP 运算、采购计划及生产执行报表。
|
||
- **仓储/生产领料(Warehouse/Issue)**:工单领料单及出库明细。
|
||
- **研发(RD/Ebom)**:工程 BOM(EBOM)维护。
|
||
- **系统管理(System)**:用户、角色、部门、岗位等组织架构。
|
||
|
||
各模块页面组件基本遵循:
|
||
|
||
- `index.vue`:列表、搜索、分页、批量操作
|
||
- `form.vue`:单据新增/编辑/查看(通常由路由 `new` / `edit/:id` / `view/:id` 复用)
|
||
|
||
---
|
||
|
||
## 5. 开发约定与最佳实践
|
||
|
||
1. **类型优先**
|
||
- 所有接口数据结构优先在 `src/api/*` 中通过 `interface`/`type` 定义。
|
||
- 组件中通过 `import type Xxx from '@/api/xxx'` 复用类型,避免魔法字符串和隐式 `any`。
|
||
|
||
2. **单据模式一致**
|
||
- 列表页负责查询、分页、批量操作。
|
||
- 单据表单页负责单据的增删改查、审批、导出、引入等。
|
||
- 路由命名尽量统一(如 `XxxList`、`XxxNew`、`XxxEdit`、`XxxView`)。
|
||
|
||
3. **API 调用约定**
|
||
- 列表类:`getXxxList(params)` / `getXxxDocList(params)` / `getXxxSummary(params)`。
|
||
- 单据类:`getXxx(id)` / `createXxx(data)` / `updateXxx(data)` / `deleteXxx(id)` / `approveXxx(id)`。
|
||
- 导出类:`exportXxx(params)` 返回 `Blob`,前端统一通过 `URL.createObjectURL` 下载。
|
||
|
||
4. **错误处理**
|
||
- 全局拦截器负责大部分 HTTP 错误提示。
|
||
- 业务逻辑错误(如必填字段缺失、状态不允许操作)应在组件内通过 `ElMessage` 或 `ElMessageBox` 友好提示。
|
||
|
||
5. **国际化与文案**
|
||
- 当前以中文为主,业务文案尽量统一、简洁。
|
||
- 后续如需多语言,可在布局和组件中收口文案位置,方便替换。
|
||
|
||
---
|
||
|
||
## 6. 新功能迭代指南
|
||
|
||
以新增一个简单业务模块为例,推荐步骤如下:
|
||
|
||
1. **定义后端接口与数据结构**
|
||
- 与后端约定好 URL、请求方式以及返回结构。
|
||
- 在 `src/api/<module>.ts` 中新增对应的接口类型定义与请求函数。
|
||
|
||
2. **新增页面组件**
|
||
- 在 `src/views/<Module>/<Feature>/` 下创建:
|
||
- `index.vue`:列表页
|
||
- `form.vue`:单据表单页(可根据是否需要拆分为 new/edit/view 来复用)
|
||
- 使用 `<script setup lang="ts">`,并引入上一步定义的类型。
|
||
|
||
3. **注册路由**
|
||
- 在 `src/router/index.ts` 中对应业务分组下新增子路由:
|
||
- 列表:`/module/feature`
|
||
- 新增:`/module/feature/new`
|
||
- 编辑:`/module/feature/edit/:id`
|
||
- 查看:`/module/feature/view/:id`
|
||
- 配置好 `name` 和 `meta.title`,以便面包屑与标题显示。
|
||
|
||
4. **加入侧边菜单**
|
||
- 在 `src/layout/index.vue` 左侧菜单中增加对应菜单项,index 与路由 path 对齐。
|
||
|
||
5. **权限控制(如需要)**
|
||
- 后端返回对应的角色/权限字符串。
|
||
- 在前端根据 `userStore.hasRole` / `hasPermission` 决定是否展示按钮或入口。
|
||
|
||
6. **编写/更新测试**
|
||
- 对复杂的计算逻辑或数据加工函数,建议抽到独立模块并使用 Vitest 编写单元测试。
|
||
- 对关键表单组件或流程,使用 `@vue/test-utils` + Vitest 编写基础渲染和交互用例。
|
||
|
||
7. **自测与提交**
|
||
- 运行 `npm run dev` 手动验证主要流程。
|
||
- 运行 `npm run test` 和 `npm run build` 确认无测试失败与类型错误。
|
||
|
||
---
|
||
|
||
## 7. Bug 修复与调试建议
|
||
|
||
1. **快速定位问题**
|
||
- TS 编译错误:优先通过 `npm run build` 或 `vue-tsc -b` 定位。
|
||
- 运行时错误:查看浏览器控制台和网络请求(Network)日志。
|
||
|
||
2. **保持类型一致**
|
||
- 修复字段名或结构变更时,同步更新:
|
||
- 对应的 API 接口类型定义(`src/api/*`)
|
||
- 所有使用该类型的组件
|
||
|
||
3. **避免静默失败**
|
||
- catch 到错误时,优先使用 `ElMessage.error` 告知用户(同时 `console.error` 方便开发排查)。
|
||
|
||
4. **回归检查**
|
||
- 对涉及核心单据(生产计划、采购计划、销售订单、领料单等)的改动,建议:
|
||
- 至少完成一次完整的“从主数据 → 业务单据 → 报表/导出”的端到端手工验证。
|
||
- 补充或更新相应的单元测试。
|
||
|
||
---
|
||
|
||
## 8. 测试用例编写建议
|
||
|
||
项目已集成 Vitest 与 Vue Test Utils,可按以下思路补充测试:
|
||
|
||
1. **纯逻辑/工具函数**
|
||
- 放在独立的 `utils` 或 `helpers` 文件中。
|
||
- 使用 Vitest 编写函数级单元测试,覆盖数字计算、状态映射等逻辑。
|
||
|
||
2. **API 封装**
|
||
- 使用 Vitest 的 mocking 能力(如 `vi.mock('axios')`)对 API 模块进行单元测试,确保在不同返回结构下都有正确行为。
|
||
|
||
3. **组件/页面**
|
||
- 使用 `@vue/test-utils` 挂载组件,测试:
|
||
- 基本渲染是否正常(必需字段/按钮是否存在)
|
||
- 关键交互(点击按钮后是否发出预期事件或调用 API)
|
||
- 表单校验逻辑(缺失必填项时是否提示)
|
||
|
||
4. **回归测试**
|
||
- 对已修复的 Bug,尽量补一条对应的测试用例,避免同类问题再次出现。
|
||
|
||
---
|
||
|
||
如需在后续迭代中扩展架构(例如引入 Pinia、国际化、多布局支持等),可以在本 README 继续追加对应的小节,保持文档与实现同步更新。
|