commit content

This commit is contained in:
panchengyong
2026-03-06 02:02:59 +08:00
parent 99b07682e7
commit c28ada5050
733 changed files with 128794 additions and 248 deletions

View File

@@ -0,0 +1,147 @@
---
name: Mbom editable material list
overview: 在生产计划单表单的物料清单区域中,将供应方式、下发车间、下发时间、下发状态等列从只读改为可编辑,并在后端新增 issue_date 字段,前端对接已有的 updateMbom 和 issueToWorkshop 接口。
todos:
- id: db-migration
content: 新建 SQL 脚本,在 erp_mp_mbom 表新增 issue_date 列
status: completed
- id: backend-entity
content: 修改 MpMbom.java 新增 issueDate 字段及 getter/setter
status: completed
- id: backend-mapper
content: 修改 MpMbomMapper.xml 新增 issue_date 列映射、插入、更新
status: completed
- id: frontend-types
content: 更新 productionPlan.ts 和 mbom.ts 的接口定义,新增 mbomId、workshopId、issueDate
status: completed
- id: frontend-form
content: 改造 form.vue 物料清单表格:供应方式/下发车间/下发时间/下发状态改为可编辑
status: completed
- id: frontend-save
content: 新增物料清单行级别保存逻辑,对接 updateMbom/issueToWorkshop API
status: completed
isProject: false
---
# 生产计划单 - 物料清单可编辑功能
## 现状分析
生产计划单表单 [form.vue](erp-frontend-vue/src/views/Production/PlanOrder/form.vue) 中的"物料清单"区域(第 240-283 行)目前所有列均为只读展示。
后端已有的接口能力:
- `PUT /erp/mp/mbom` — 更新物料清单整体(含 supplyType、workshopId、workshopName、issueStatus
- `PUT /erp/mp/mbom/issue/{mbomId}/{workshopId}/{workshopName}` — 下发到车间
- 车间列表 API`GET /mes/md/workshop/list`
**缺失**:后端 `MpMbom` 实体和数据库表 `erp_mp_mbom` 中没有 `issue_date`(下发时间)字段。
## 修改方案
### 第一部分:后端 - 新增 issue_date 字段
**1. 数据库 SQL**
新建迁移脚本,在 `erp_mp_mbom` 表新增 `issue_date` 列:
```sql
ALTER TABLE erp_mp_mbom ADD COLUMN issue_date datetime DEFAULT NULL COMMENT '下发时间' AFTER issue_status;
```
**2. Java 实体 [MpMbom.java**](mom-backend/ktg-mes/src/main/java/com/ktg/mes/mp/domain/MpMbom.java)
`issueStatus` 字段后新增:
```java
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "下发时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date issueDate;
```
及对应的 getter/setter。
**3. MyBatis Mapper [MpMbomMapper.xml**](mom-backend/ktg-mes/src/main/resources/mapper/mp/MpMbomMapper.xml)
- `resultMap` 增加 `<result property="issueDate" column="issue_date" />`
- `selectMpMbomVo` SQL 的列列表中增加 `issue_date`
- `insertMpMbom` 增加 issueDate 的插入
- `updateMpMbom` 增加 issueDate 的更新
**4. issueToWorkshop 方法更新**
在 [MpMbomController.java](mom-backend/ktg-mes/src/main/java/com/ktg/mes/mp/controller/MpMbomController.java) 的 `issueToWorkshop` 方法中,下发时自动设置 `issueDate = new Date()`。或者保持不变,由前端通过 `PUT /erp/mp/mbom` 自行设置 issueDate。
### 第二部分:前端 - 物料清单表格可编辑
**5. 更新 TypeScript 接口**
在 [productionPlan.ts](erp-frontend-vue/src/api/productionPlan.ts) 的 `MbomLine` 接口中增加:
```typescript
export interface MbomLine {
mbomId?: number // 新增
mbomCode?: string
mbomStatus?: string
businessType?: string
issueStatus?: string
itemCode?: string
itemName?: string
unitName?: string
supplyType?: string
productionQty?: number
workshopId?: number // 新增
workshopName?: string
issueDate?: string // 新增
}
```
在 [mbom.ts](erp-frontend-vue/src/api/mbom.ts) 的 `Mbom` 接口中增加 `issueDate?: string`
**6. 修改 [form.vue](erp-frontend-vue/src/views/Production/PlanOrder/form.vue) 物料清单表格**
将第 250-282 行的物料清单 `<el-table>` 中以下列从纯文本改为可编辑组件:
- **供应方式 (supplyType)** — 改为 `el-select`,选项:`生产/加工/采购/委外`(对应 SELF_MADE/PROCESSING/PURCHASE/OUTSOURCE并增加"转委外"快捷操作链接
- **下发车间 (workshopName)** — 改为 `el-select`,数据源为车间列表(调用 `listWorkshop` API选中后同时保存 `workshopId``workshopName`
- **下发时间 (issueDate)** — 新增列,使用 `el-date-picker` 组件
- **下发状态 (issueStatus)** — 改为 `el-switch` 组件,开 = "ISSUED" / 关 = "" 或 "PENDING"
参考截图中的交互方式:
```
| 供应方式 | 生产数量 | 下发车间 | 操作 |
| 生产 [转委外] | 970 | 加工车间 [开关] 2026-02-10 | 齐套/BOM/生产 |
| 加工 [转委外] | 970 | 装配车间 [开关] 2026-02-11 | 齐套/BOM/生产 |
```
**7. 新增数据和方法**
-`<script setup>` 中引入 `listWorkshop` API 并加载车间列表
- 引入 `updateMbom``issueToWorkshop` API
- 新增 `handleMbomSupplyTypeChange(row, val)` — 调用 updateMbom 保存供应方式
- 新增 `handleMbomWorkshopChange(row, workshop)` — 更新 workshopId/workshopName
- 新增 `handleMbomIssueToggle(row)` — 切换下发状态,开时调用 issueToWorkshop + 设置 issueDate
- 新增 `handleMbomIssueDateChange(row, date)` — 更新 issueDate
- 新增 `saveMbomRow(row)` — 通用保存方法,调用 `updateMbom`
- 编辑条件判断:仅当生产计划已审核 (`isOrderApproved`) 且物料清单存在时允许编辑
**8. 更新 loadPlanData 中 mbomList 映射**
`loadPlanData()` 方法(第 677 行)中映射 mbomList 时,确保 `mbomId``workshopId``issueDate` 等新字段被正确保留。
## 涉及的文件
后端:
- [MpMbom.java](mom-backend/ktg-mes/src/main/java/com/ktg/mes/mp/domain/MpMbom.java) — 新增 issueDate 字段和 getter/setter
- [MpMbomMapper.xml](mom-backend/ktg-mes/src/main/resources/mapper/mp/MpMbomMapper.xml) — 新增 issue_date 列映射
- [MpMbomController.java](mom-backend/ktg-mes/src/main/java/com/ktg/mes/mp/controller/MpMbomController.java) — issueToWorkshop 方法设置 issueDate可选
- 新建 SQL 迁移脚本
前端:
- [productionPlan.ts](erp-frontend-vue/src/api/productionPlan.ts) — MbomLine 接口扩展
- [mbom.ts](erp-frontend-vue/src/api/mbom.ts) — Mbom 接口扩展
- [form.vue](erp-frontend-vue/src/views/Production/PlanOrder/form.vue) — 物料清单表格改为可编辑 + 新增保存逻辑

View File

@@ -0,0 +1,446 @@
---
name: MOM-UI Tech Stack Migration
overview: 将 mom-backend-ui 从 Vue CLI + Vue 2 + Element UI 渐进式升级到 Vite + Vue 3 + Element Plus与 erp-frontend-vue 技术栈保持一致,方便后续合并。
todos:
- id: phase1-vite-setup
content: "Phase 1: 创建 vite.config.js移动 index.html 到根目录,更新 package.json scripts安装 Vite + Vue 3 + @vue/compat 依赖,移除 Vue CLI/Webpack 依赖"
status: completed
- id: phase2-core-modules
content: "Phase 2: 更新 main.js (createApp),升级 Vue Router 4升级 Vuex 4替换 SVG 图标系统 (vite-plugin-svg-icons),修改 permission.js"
status: completed
- id: phase3a-element-plus-deps
content: "Phase 3a: 替换 Element Plus 依赖 + 更新 main.js 导入 + 迁移公共组件 (31 个 dialog 组件) + 迁移采购入库页面 (4 个 Vue 文件) 作为验证试点"
status: in_progress
- id: phase3a-2-layout-components
content: "Phase 3a-2: 迁移 src/layout/ + src/components/ 中非 dialog 组件 (~38 个 Vue 文件),确保公共组件完全脱离 Element UI"
status: completed
- id: phase3b-wm-module
content: "Phase 3b: 迁移仓库管理模块其余页面 (wm, 64 个 Vue 文件),验证整个模块功能正常"
status: pending
- id: phase3c-remaining-pages
content: "Phase 3c: 迁移其余所有页面 (MES 其他 98 + system 19 + monitor 8 + tool 12 + print 6 + 其他 5 = ~148 个 Vue 文件) + 全局样式修正"
status: pending
- id: phase4-third-party
content: "Phase 4: 更新第三方依赖为 Vue 3 兼容版本 (vuedraggable, vue-cropper, echarts, quill, axios 等)"
status: completed
- id: phase5-cleanup
content: "Phase 5: 删除旧配置文件,迁移环境变量 (VUE_APP_ -> VITE_),移除 @vue/compat,最终清理"
status: pending
isProject: false
---
# mom-backend-ui 技术栈升级计划
## 当前差异对比
| 维度 | mom-backend-ui (当前) | erp-frontend-vue (目标) |
| ------ | ----------------------------------- | -------------------------------- |
| 构建工具 | Vue CLI 4 (Webpack) | Vite 7 |
| 框架 | Vue 2.6 | Vue 3.5 |
| UI 库 | Element UI 2.15 | Element Plus 2.x |
| 路由 | Vue Router 3.4 | Vue Router 4.6 |
| 状态管理 | Vuex 3.6 | 自定义 reactive store |
| 语言 | JavaScript | TypeScript (暂保留 JS) |
| 组件风格 | Options API | Composition API `<script setup>` |
| SVG 图标 | svg-sprite-loader + require.context | @element-plus/icons-vue |
## 核心挑战
项目有 **305 个 Vue 文件 + 225 个 JS 文件**,无法一步到位。采用 **Vue 3 兼容模式 (`@vue/compat`)** 进行渐进式迁移,确保大部分 Vue 2 代码可以在 Vue 3 下运行,然后逐步修复。
---
## Phase 1: Vite 构建工具替换 + Vue 3 兼容模式
### 1.1 创建 Vite 配置
在 [mom-backend-ui/](mom-backend-ui/) 根目录创建 `vite.config.js`,参考 [erp-frontend-vue/vite.config.ts](erp-frontend-vue/vite.config.ts) 的结构:
```javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
iconDirs: [path.resolve(__dirname, 'src/assets/icons/svg')],
symbolId: 'icon-[name]'
})
],
resolve: {
alias: { '@': path.resolve(__dirname, './src') },
// Vue 3 compat mode
dedupe: ['vue']
},
server: {
port: 80,
proxy: {
'/dev-api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/dev-api/, '')
},
'/ureport': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
},
css: {
preprocessorOptions: {
scss: { api: 'modern-compiler' }
}
}
})
```
### 1.2 移动并更新 index.html
将 [mom-backend-ui/public/index.html](mom-backend-ui/public/index.html) 移到项目根目录,移除 Webpack 模板语法:
- `<%= BASE_URL %>` 改为 `/`
- `<%= webpackConfig.name %>` 改为固定标题
- 添加 `<script type="module" src="/src/main.js"></script>`
### 1.3 更新 package.json
- 添加 `"type": "module"`
- 更新 scripts
- `"dev": "vite"`
- `"build": "vite build"`
- `"preview": "vite preview"`
### 1.4 安装新依赖,移除旧依赖
**安装:**
- `vue@^3.5` + `@vue/compat@^3.5`(兼容模式)
- `vite` + `@vitejs/plugin-vue`
- `vite-plugin-svg-icons` + `fast-glob`(替代 svg-sprite-loader
- `sass-embedded`(替代 sass + sass-loader
**移除:**
- `@vue/cli-service`, `@vue/cli-plugin-babel`, `@vue/cli-plugin-eslint`
- `vue-template-compiler`
- `webpack` 相关: `compression-webpack-plugin`, `script-ext-html-webpack-plugin`, `svg-sprite-loader`, `sass-loader`, `less-loader`
- `babel-eslint`, `babel-plugin-dynamic-import-node`, `cross-env`
- `core-js`
### 1.5 配置 @vue/compat
`vite.config.js` 中配置别名,让 `vue` 指向兼容构建:
```javascript
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'vue': '@vue/compat'
}
}
```
同时需要配置 `@vitejs/plugin-vue` 的 compat 编译器选项:
```javascript
vue({
template: {
compilerOptions: {
compatConfig: { MODE: 2 }
}
}
})
```
---
## Phase 2: 更新入口文件和核心模块
### 2.1 更新 main.js
将 [mom-backend-ui/src/main.js](mom-backend-ui/src/main.js) 从 `new Vue()` 改为 `createApp()`
- `import { createApp } from 'vue'` 替代 `import Vue from 'vue'`
- `const app = createApp(App)` 替代 `new Vue({...})`
- `Vue.prototype.xxx` 改为 `app.config.globalProperties.xxx`
- `Vue.component(...)` 改为 `app.component(...)`
- `Vue.use(...)` 改为 `app.use(...)`
- `app.use(store).use(router).mount('#app')`
### 2.2 更新 SVG 图标系统
将 [mom-backend-ui/src/assets/icons/index.js](mom-backend-ui/src/assets/icons/index.js) 中的 `require.context` 替换为 Vite 的 `import.meta.glob`
```javascript
import 'virtual:svg-icons-register'
// SvgIcon 组件需要在 main.js 中用 app.component 注册
```
### 2.3 升级 Vue Router 3 -> 4
修改 [mom-backend-ui/src/router/index.js](mom-backend-ui/src/router/index.js)
- `import { createRouter, createWebHistory } from 'vue-router'`
- `new Router({mode: 'history', ...})` 改为 `createRouter({ history: createWebHistory(), ... })`
- 移除 `Vue.use(Router)`
- `scrollBehavior: () => ({ y: 0 })` 改为 `scrollBehavior: () => ({ top: 0 })`
修改 [mom-backend-ui/src/permission.js](mom-backend-ui/src/permission.js)
- `router.addRoutes(accessRoutes)` 改为循环调用 `router.addRoute(route)`
- `Message` 从 Element Plus 导入
### 2.4 升级 Vuex 3 -> 4
修改 [mom-backend-ui/src/store/index.js](mom-backend-ui/src/store/index.js)
- `import { createStore } from 'vuex'`
- `new Vuex.Store({...})` 改为 `createStore({...})`
- 移除 `Vue.use(Vuex)`
- 各 modules 文件暂时不动Vuex 4 向后兼容 module 写法)
---
## Phase 3: Element UI -> Element Plus 迁移(分步进行)
这是工作量最大的部分,影响所有 306 个 Vue 文件。为保证项目平稳升级,拆分为 **3a → 3b → 3c** 三步,先拿采购入库页面做试点验证,确认方案可行后再逐步扩展到全模块。
### Element UI -> Element Plus 通用变更清单
以下变更适用于所有步骤,每步迁移页面时需逐项检查:
- **size 属性**: `size="mini"` -> `size="small"`, `size="medium"` -> `size="default"`
- **图标**: `<i class="el-icon-xxx">` -> `<el-icon><Xxx /></el-icon>` 或对应 Element Plus 图标组件
- **v-model 变更**: `.sync` 修饰符移除,改用 `v-model:propName`
- `:visible.sync` -> `v-model`Dialog
- `:current-page.sync` -> `v-model:current-page`Pagination
- `:page-size.sync` -> `v-model:page-size`Pagination
- **事件名变更**: `@current-change` 等部分组件事件保持不变;`.native` 修饰符移除
- **Slot 变更**: 部分具名插槽名称变化
- **移除的属性**: `el-button``type="text"` 改为 `link``text` 属性
- **DatePicker**: `value-format` 格式字符串变更 (如 `yyyy-MM-dd` -> `YYYY-MM-DD`)
---
### Phase 3a: 替换依赖 + 迁移公共组件 + 采购入库页面试点
**目标**: 完成 Element Plus 基础切换,优先迁移 `src/components` 中的公共组件(避免页面迁移时遇到依赖问题),再以采购入库页面(`itemrecpt`)作为验证试点。
#### 3a.1 替换依赖
- 卸载 `element-ui`
- 安装 `element-plus` + `@element-plus/icons-vue`
- 删除 [mom-backend-ui/src/assets/styles/element-variables.scss](mom-backend-ui/src/assets/styles/element-variables.scss),改用 Element Plus 主题配置
#### 3a.2 更新 main.js 中的 Element 导入
```javascript
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// 注册图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(ElementPlus, { locale: zhCn, size: 'default' })
```
#### 3a.3 更新 plugins/modal.js 中的 Element 导入
`import { Message, MessageBox, Notification, Loading } from 'element-ui'` 改为 `import { ElMessage, ElMessageBox, ElNotification, ElLoading } from 'element-plus'`,并更新对应的 API 调用。
同时更新 `permission.js` 中的 `Message` 导入。
#### 3a.4 迁移公共组件31 个包含 Dialog 的组件,优先处理)
**目标**: 修复所有 `src/components` 中使用 `:visible.sync` 的组件,避免页面迁移时遇到 `[ElOnlyChild]` 错误。
需要迁移的组件列表(按目录分组):
| 组件分类 | 文件路径 | 数量 |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- |
| Select 组件 | vendorSelect, iqcSelect, noticeSelect, itemSelect, clientSelect, batchSelect, userSelect, stockSelect, machinerySelect, warehouseSelect, workstationSelect, workorderSelect, procardSelect, qcindexSelect, reportSelect, TaskSelect, defectSelect, dvsubjectSelect, calTeamSelect, oqcSelect, itemBomSelect, dvplanSelect, stocktakingplanSelect, package | 31 |
| 其他 | DictSelect, ImageUpload | 2 |
**关键变更点**(适用所有组件):
- `:visible.sync="showFlag"` -> `v-model="showFlag"`
- 移除 `v-if="showFlag"`Element Plus dialog 自带显示控制)
- `<el-dialog>` 必须有单个根元素:添加 `<div class="dialog-content-wrapper">` 包裹所有 slot 默认内容
- `<div slot="footer">` -> `<template #footer>`
**当前进度**(已完成部分):
- ✅ vendorSelect/single.vue
- ✅ iqcSelect/single.vue
- ✅ noticeSelect/single.vue
- ⏳ noticeSelect/lineSingle.vue (进行中)
- ⏳ itemSelect/single.vue (进行中)
- 🔲 其余 26 个组件待迁移
#### 3a.5 迁移采购入库页面(试点验证)
逐一修改以下 4 个文件,按照通用变更清单做 Element Plus 适配:
| 文件 | 说明 |
| --------------------------------------- | ------- |
| `src/views/mes/wm/itemrecpt/index.vue` | 采购入库列表页 |
| `src/views/mes/wm/itemrecpt/form.vue` | 采购入库表单页 |
| `src/views/mes/wm/itemrecpt/line.vue` | 采购入库明细行 |
| `src/views/mes/wm/itemrecpt/detail.vue` | 采购入库详情页 |
**验收标准**: 启动 `vite dev`,能正常访问采购入库列表、新增、编辑、查看详情,无控制台报错。
---
### Phase 3a-2: 迁移公共布局和非 Dialog 组件(~38 个 Vue 文件)
**目标**: 完成 `src/layout/``src/components/` 中剩余的非 dialog 组件迁移,确保所有公共组件脱离 Element UI。
#### 需要迁移的文件类型
**Layout 组件** (`src/layout/`):
- Layout 主布局组件
- Navbar, Sidebar, TagsView 等导航组件
- AppMain, Settings 等布局子组件
- 约 10-15 个文件
**非 Dialog 公共组件** (`src/components/`):
- Pagination分页组件
- FileUpload文件上传
- Editor富文本编辑器可能使用 Element UI 依赖)
- Breadcrumb面包屑
- SvgIconSVG 图标,已迁移)
- Dict 相关组件(数据字典)
- TreeSelect, Cascader 等表单组件
- 其他工具类组件(约 20-25 个文件)
**迁移要点**:
- 替换所有 Element UI 组件为 Element Plus
- 更新 `size="mini"` -> `size="small"`
- 移除 `.native` 修饰符
- 更新图标引用方式
- 检查并修复任何使用 `$message`, `$alert` 等全局方法的调用
**验收标准**: 所有 `src/components/``src/layout/` 文件中不再有 `element-ui` 导入,项目启动无 Element UI 相关警告。
---
### Phase 3b: 仓库管理模块其余页面64 个 Vue 文件)
**目标**: 确认试点方案可行后,将整个仓库管理模块(`views/mes/wm/`)全部迁移完成。
需要迁移的子模块(按业务分组):
| 分组 | 子模块 | 文件数 |
| --- | -------------------------------------------------------------------------------------------------------- | --- |
| 入库 | arrivalnotice (到货通知), itemrecpt (采购入库✅已完成), outsourcerecpt (委外入库), productrecpt (产品入库), miscrecpt (其他入库) | ~15 |
| 出库 | issue (生产领料), productsales (销售出库), outsourceissue (委外出库), miscissue (其他出库), itemconsume (物料消耗) | ~15 |
| 退料 | rtissue (生产退料), rtsales (销售退货), rtvendor (供应商退货) | ~9 |
| 库存 | wmstock (库存查询), stocktaking (盘点), stocktakingplan (盘点计划), transfer (调拨) | ~10 |
| 基础 | warehouse (仓库), location (库区), area (库位), barcode (条码), batch (批次), sn (序列号), package (包装) | ~13 |
| 通知 | salesnotice (销售通知), mrnotice (物料需求通知) | ~5 |
**验收标准**: 仓库管理菜单下所有页面(列表/表单/详情)均可正常操作,无控制台 Element 组件报错。
---
### Phase 3c: 其余所有页面(~148 个 Vue 文件)+ 全局样式修正
**目标**: 完成所有剩余页面的迁移,项目彻底脱离 Element UI。
| 分组 | 范围 | 文件数 |
| ------ | ------------------------------------------------------------ | --- |
| MES 其他 | `views/mes/` 除 wm 外 (md, pro, dv, qc, report 等) | ~98 |
| 系统管理 | `views/system/` (user, role, menu, dept, dict 等) | ~19 |
| 监控 | `views/monitor/` (online, job, server, cache 等) | ~8 |
| 工具 | `views/tool/` (gen, build 等) | ~12 |
| 打印 | `views/print/` | ~6 |
| 其他 | `views/login.vue`, `views/register.vue`, `views/index.vue` 等 | ~5 |
#### 3c.1 全局样式文件更新
- 更新 [mom-backend-ui/src/assets/styles/](mom-backend-ui/src/assets/styles/) 下的 SCSS 文件中引用 Element UI 类名的部分
- Element Plus 的 CSS 变量命名有差异(如 `--el-color-primary` 等)
- `el-icon-loading` spinner 等全局引用需更新
**验收标准**: 全站所有页面功能正常,无 Element UI 残留引用,`vite build` 成功。
---
## Phase 4: 更新第三方依赖
以下 Vue 2 专属库需要更新为 Vue 3 兼容版本:
| 当前依赖 | 操作 |
| ------------------------- | ------------------------------------------------- |
| `vue-meta` 2.x | 移除,改用 `@unhead/vue``document.title` |
| `vuedraggable` 2.x | 升级到 `vuedraggable@next` (4.x) |
| `vue-cropper` 0.5 | 升级到 `vue-cropper@next` |
| `@riophae/vue-treeselect` | 替换为 `vue3-treeselect` 或 Element Plus 的 TreeSelect |
| `vue-count-to` | 替换为 Vue 3 兼容版本或自行实现 |
| `vue-plugin-hiprint` | 确认 Vue 3 兼容性,可能需要替换 |
| `echarts` 4.9 | 升级到 5.x |
| `@dhtmlx/trial-vue-gantt` | 确认 Vue 3 兼容版本 |
| `quill` | 替换为 `@vueup/vue-quill` |
| `axios` 0.24 | 升级到 1.x |
---
## Phase 5: 清理和收尾
### 5.1 移除旧配置文件
- 删除 `vue.config.js`
- 删除 `babel.config.js`
- 删除 `.eslintrc.js`(后续可按需重新配置 ESLint flat config
- 删除 `build/` 目录preview 脚本)
### 5.2 移除 @vue/compat
当所有组件和功能正常运行后:
-`vite.config.js` 中移除 `'vue': '@vue/compat'` 别名
- 移除 `compatConfig` 编译器选项
- 卸载 `@vue/compat`
- 修复剩余的 Vue 2 兼容性警告
### 5.3 环境变量迁移
- `VUE_APP_*` 环境变量需改为 `VITE_*` 前缀
- `process.env.VUE_APP_*` 改为 `import.meta.env.VITE_*`
- 创建 `.env.development``.env.production` 文件
---
## 执行建议
- **Phase 1-2** 是基础,已完成,项目可用 `vite` 启动和构建
- **Phase 3a** 先做依赖切换 + 采购入库试点,验证迁移方案的完整流程和模式
- **Phase 3b** 试点通过后,在仓库管理模块内推广,以模块为单位验证
- **Phase 3c** 最后全面铺开,涵盖剩余 layout/components/views
- **Phase 4** 可以与 Phase 3 并行,按需处理
- **Phase 5** 在所有功能验证通过后进行
- 整个过程中暂保留 JavaScript不转 TypeScript后续按需迁移
- 每步完成后都应启动 `vite dev` 实际操作验证,确认无功能回退再进入下一步

View File

@@ -0,0 +1,129 @@
---
name: Optimize Production Plan Page
overview: Based on the PRD v1.5.0 gap analysis, fix a critical form-disabled bug that blocks MBOM editing in view mode, and implement missing features including view-page toolbar buttons, EBOM detail dialog, supply type ASSEMBLY option, list-page clickable columns, and several UX improvements.
todos:
- id: fix-form-disabled
content: "P0: 修复 el-form disabled 阻断 MBOM 编辑 -- 将物料清单/补料清单 section 移出 el-form 包裹"
status: completed
- id: view-toolbar
content: "P1: 查看页顶部工具栏添加「新增」「编辑」按钮"
status: completed
- id: ebom-view-dialog
content: "P1: 表头订单BOM添加「查看」按钮 + EBOM详情弹窗"
status: completed
- id: supply-type-assembly
content: "P1: 供应方式选项添加 ASSEMBLY(装配)"
status: completed
- id: list-material-dialog
content: "P1: 列表页明细视图物料名称/物料清单列可点击弹窗"
status: completed
- id: edit-btn-behavior
content: "P2: 单据视图已审核行编辑按钮改为跳转查看页"
status: completed
- id: view-switch-style
content: "P2: 视图切换按钮添加 type=primary 样式"
status: completed
- id: import-dialog-enhance
content: "P2: 引入订单弹窗优化 -- 层级展开表格、日期搜索、查询所有按钮"
status: completed
- id: record-navigation
content: "P2: 查看/编辑页实现上一条/下一条记录导航"
status: completed
isProject: false
---
# 完善优化生产计划单页面
## 差距分析总览
对比 PRD v1.5.0 与当前代码,发现以下需要修复和完善的问题:
---
## P0 - 关键缺陷
### 1. 查看模式下 MBOM 编辑被 el-form disabled 阻断
**问题**: [form.vue](erp-frontend-vue/src/views/Production/PlanOrder/form.vue) 第 36 行 `<el-form :disabled="isView">` 包裹了整个页面内容包括物料清单子表。Element Plus 的 `el-form disabled` 会通过 provide/inject 传递给所有后代表单组件el-switch、el-select、el-date-picker、el-button导致即使 `canEditMbom``true`,查看模式下所有 MBOM 编辑控件仍然被禁用。
**修复**: 将物料清单子表和补料清单子表移出 `<el-form :disabled="isView">` 的包裹范围。具体做法:在 `</el-form>` (line 385) 之前关闭 form 标签,将物料清单和补料清单 section 移到 form 外面。表头和订单信息子表保留在 form 内(编辑时需要验证)。
---
## P1 - 功能缺失PRD 明确要求)
### 2. 查看页顶部工具栏缺少按钮PRD 6.3.13
**现状**: 查看页仅显示 审核、反审核、收起 三个按钮。
**PRD 要求**: 查看页应显示 新增、编辑、审核、反审核、收起。
**修复**: 在 [form.vue](erp-frontend-vue/src/views/Production/PlanOrder/form.vue) 第 8-32 行的 `header-right` 区域,为 `isView` 模式添加「新增」和「编辑」按钮:
- 新增: 跳转 `/production/plan-order/new`
- 编辑: 跳转 `/production/plan-order/edit/{planId}`(仅开立状态启用)
### 3. 订单BOM「查看」按钮 + EBOM 详情弹窗PRD 6.3.9 / 7.6.5
**现状**: 表头「订单BOM」仅有「选择」按钮编辑模式。查看模式或已选择 BOM 后无法查看 EBOM 详情。
**PRD 要求**: 已选择 BOM 时(查看/编辑页),显示「查看」按钮打开 EBOM 详情弹窗。
**修复**:
- 在表头「订单BOM」字段旁`formData.bomId` 存在时显示「查看」链接按钮
- 新增 EBOM 详情弹窗组件: 显示 EBOM 信息EBOM单号、业务类型、物料编码、物料名称、属性母件基数、图纸号、版本号、版本说明、BOM 组件表(序号、物料编码、物料名称、主计量、领料方式、分子、固定用量)
- 复用已有的 `getEbom` API 和 `EbomLine` 类型
### 4. 供应方式选项缺少「装配」PRD 4.4 / 附录A
**现状**: `SUPPLY_TYPE_OPTIONS` (line 650-655) 只有 4 个选项: SELF_MADE(生产)、PROCESSING(加工)、PURCHASE(采购)、OUTSOURCE(委外)
**PRD 要求**: 应有 5 个选项,包含 ASSEMBLY(装配)
**修复**: 在 `SUPPLY_TYPE_OPTIONS` 中添加 `{ value: 'ASSEMBLY', label: '装配' }`
### 5. 列表页明细视图 - 物料名称/物料清单列可点击弹窗PRD 7.2 #3 / 7.6.2
**现状**: [index.vue](erp-frontend-vue/src/views/Production/PlanOrder/index.vue) 中「物料名称」(line 189) 和「物料清单」(line 197-201) 列为纯文本展示,不可点击。
**PRD 要求**: 点击应弹出物料清单明细弹窗:标题「{计划编码} {物料编码} {物料名称} {数量} - 物料清单」,表格列:序号、物料编码、物料名称、主计量、需求量、可用量、领用量、供应方式。
**修复**:
- 将这两列改为 `el-link` 可点击
- 新增物料清单明细弹窗(`el-dialog`),调用 MBOM 相关 API 获取物料清单数据并展示
- 需新增 API: 根据 planId + itemId 查询 MBOM lines (或复用 `getMbomLines`)
---
## P2 - 功能增强
### 6. 单据视图编辑按钮行为优化PRD 3.2.4 注意)
**现状**: 已审核状态的编辑按钮 disabled。
**PRD 说明**: "已审核状态的编辑实际以查看模式打开"。
**修复**: [index.vue](erp-frontend-vue/src/views/Production/PlanOrder/index.vue) 第 253-260 行,已审核状态的编辑按钮不再 disabled改为点击后跳转查看页 (`/view/`) 而非编辑页。
### 7. 视图切换按钮样式PRD 6.1.1 / 6.2.1
**现状**: 切换按钮无 type。
**PRD 要求**: 「单据」「明细」切换按钮应为 `type="primary"`
**修复**: 给 [index.vue](erp-frontend-vue/src/views/Production/PlanOrder/index.vue) 第 108-119 行的切换按钮添加 `type="primary"`
### 8. 引入订单弹窗优化PRD 4.6 / 7.6.3
**现状**: 弹窗是平铺的订单列表,无层级展开,无日期范围搜索,「重置」按钮而非「查询所有」。
**PRD 要求**: 层级表格(父行=订单头可展开,子行=订单明细),搜索区含开始/结束日期,按钮名为「查询所有」。
**修复**:
- 搜索区增加 开始日期、结束日期
- 重置按钮改名为「查询所有」
- 表格改为可展开行模式: 父行显示业务人员、业务单号、订单交期等,展开后显示订单明细行
### 9. 记录导航「上一条」「下一条」PRD 6.3.12 / 7.6.8
**现状**: 未实现。
**PRD 要求**: 查看/编辑模式下,当存在多条计划记录时显示上一条/下一条导航按钮。
**修复**: 在 form.vue 的 header-left 区域添加导航按钮,需要维护一个计划 ID 列表(可从列表页通过 route query 传入或调用 list API 获取相邻记录)。
---
## 涉及文件
- `erp-frontend-vue/src/views/Production/PlanOrder/form.vue` -- P0 #1, P1 #2/3/4, P2 #8/9
- `erp-frontend-vue/src/views/Production/PlanOrder/index.vue` -- P1 #5, P2 #6/7
- `erp-frontend-vue/src/api/productionPlan.ts` -- P1 #5 (可能需要新增 API)

View File

@@ -0,0 +1,265 @@
---
name: Production Issue Module
overview: Create the full production material requisition (生产领料单) module under Warehouse, including 3 API files, router configuration, list page, and a form page with header/line/detail three-level data management, following existing codebase patterns.
todos:
- id: api-layer
content: "创建 3 个 API 文件: src/api/warehouse/issue.ts, issueLine.ts, issueDetail.ts包含类型定义、状态常量和所有 CRUD + 业务接口"
status: completed
- id: router-config
content: 在 router/index.ts 中追加 /warehouse 路由组,包含 issue 的 list/new/edit/view 四条路由
status: completed
- id: list-page
content: 创建 src/views/Warehouse/Issue/index.vue 列表页:搜索区(7字段) + 工具栏(4按钮) + 表格(11列+操作列) + 分页 + 删除/出库校验逻辑
status: completed
- id: form-header
content: 创建 src/views/Warehouse/Issue/form.vue 表头部分:页面框架 + el-collapse 表头表单(16字段, 4列布局) + 模式判断(isAdd/isEdit/isView) + 保存/取消/收起按钮
status: completed
- id: form-line-table
content: form.vue 领料行子表:可编辑 el-table + 添加行 + 物料选择 + 领料数量输入 + 行CRUD
status: completed
- id: form-detail-table
content: form.vue 出库明细子表:选中行后展示 + 仓库/库区/库位三级联动 el-select + 出库数量 + 明细CRUD
status: completed
- id: form-dialogs
content: form.vue 4个选择弹窗工单选择、物料选择、客户选择、工作站选择搜索+表格+单选确认
status: completed
- id: form-business
content: form.vue 业务逻辑:执行出库(checkQuantity + executeIssue)、数据加载(编辑/查看模式)、表单校验、状态控制
status: completed
- id: test-verify
content: 整体联调验证:编译检查、页面路由跳转、列表加载、新增/编辑/查看模式切换
status: completed
isProject: false
---
# 生产领料单模块开发计划
## 背景
根据 [PRD 文档](prd/mom系统生产领料单-页面开发说明文档.md),开发仓储管理下的「生产领料」功能。该模块是项目中首个 Warehouse 模块,采用 **头(Header) -> 行(Line) -> 明细(Detail)** 三层数据结构,比现有的 WorkOrder头+只读BOM子表复杂度更高。
## 核心参考
- 现有最相似模块:[Production/WorkOrder](erp-frontend-vue/src/views/Production/WorkOrder/) (index.vue + form.vue)
- API 模式:[workOrder.ts](erp-frontend-vue/src/api/workOrder.ts) (类型定义 + 状态常量 + API 函数)
- 路由模式:[router/index.ts](erp-frontend-vue/src/router/index.ts) (Layout 子路由list/new/edit/view 四条)
## 架构概览
```mermaid
graph TD
subgraph pages [页面层]
ListPage["index.vue 列表页"]
FormPage["form.vue 新增/编辑/查看页"]
end
subgraph api [API 层]
IssueAPI["issue.ts 领料单头"]
IssueLineAPI["issueLine.ts 领料行"]
IssueDetailAPI["issueDetail.ts 出库明细"]
end
subgraph backend [后端接口]
HeaderAPI["/mes/wm/issueheader/*"]
LineAPI["/mes/wm/issueline/*"]
DetailAPI["/mes/wm/issuedetail/*"]
WorkorderAPI["/mes/pro/workorder/list"]
ItemAPI["/mes/md/mditem/list"]
WarehouseAPI["/mes/wm/warehouse|location|area/list"]
end
ListPage --> IssueAPI
FormPage --> IssueAPI
FormPage --> IssueLineAPI
FormPage --> IssueDetailAPI
IssueAPI --> HeaderAPI
IssueLineAPI --> LineAPI
IssueDetailAPI --> DetailAPI
FormPage --> WorkorderAPI
FormPage --> ItemAPI
FormPage --> WarehouseAPI
```
## 文件清单
```
erp-frontend-vue/src/
├── api/
│ └── warehouse/
│ ├── issue.ts # 领料单头 API + 类型 + 状态常量
│ ├── issueLine.ts # 领料行 CRUD API + 类型
│ └── issueDetail.ts # 出库明细 CRUD API + 类型
├── views/
│ └── Warehouse/
│ └── Issue/
│ ├── index.vue # 列表页
│ └── form.vue # 新增/编辑/查看页(含行表+明细表+弹窗)
└── router/
└── index.ts # 追加 /warehouse 路由组
```
---
## 1. API 层3 个文件)
### 1.1 `src/api/warehouse/issue.ts`
- 类型:`IssueHeader`, `IssueHeaderQuery`, `IssueHeaderListResponse`
- 状态常量:`STATUS_MAP` (PREPARE/CONFIRMED/APPROVED/FINISHED)
- API 函数:
- `getIssueHeaderList(params)` -> GET `/mes/wm/issueheader/list`
- `getIssueHeaderDetail(issueId)` -> GET `/mes/wm/issueheader/{issueId}`
- `createIssueHeader(data)` -> POST `/mes/wm/issueheader`
- `updateIssueHeader(data)` -> PUT `/mes/wm/issueheader`
- `deleteIssueHeader(ids)` -> DELETE `/mes/wm/issueheader/{ids}`
- `executeIssue(issueId)` -> PUT `/mes/wm/issueheader/{issueId}` (执行出库)
- `checkQuantity(issueId)` -> GET `/mes/wm/issueheader/checkQuantity/{issueId}`
- `exportIssueHeader(params)` -> POST `/mes/wm/issueheader/export`
- 辅助 API弹窗选择
- `getWorkorderSelectList(params)` -> GET `/mes/pro/workorder/list`
- `getItemSelectList(params)` -> GET `/mes/md/mditem/list`
- `getClientSelectList(params)` -> 复用现有客户接口
- `getWarehouseList()` -> GET `/mes/wm/warehouse/list`
- `getLocationList(warehouseId)` -> GET `/mes/wm/location/list`
- `getAreaList(locationId)` -> GET `/mes/wm/area/list`
### 1.2 `src/api/warehouse/issueLine.ts`
- 类型:`IssueLine`
- API`getIssueLineList(params)`, `createIssueLine(data)`, `updateIssueLine(data)`, `deleteIssueLine(ids)`
### 1.3 `src/api/warehouse/issueDetail.ts`
- 类型:`IssueDetail`
- API`getIssueDetailList(params)`, `createIssueDetail(data)`, `updateIssueDetail(data)`, `deleteIssueDetail(ids)`
---
## 2. 路由配置
在 [router/index.ts](erp-frontend-vue/src/router/index.ts) 最后的 `]` 前追加 `/warehouse` 路由组:
```typescript
{
path: '/warehouse',
component: Layout,
redirect: '/warehouse/issue',
meta: { title: '仓储管理' },
children: [
{ path: 'issue', name: 'IssueList', component: () => import('@/views/Warehouse/Issue/index.vue'), meta: { title: '生产领料' } },
{ path: 'issue/new', name: 'IssueNew', component: () => import('@/views/Warehouse/Issue/form.vue'), meta: { title: '新增领料单' } },
{ path: 'issue/edit/:id', name: 'IssueEdit', component: () => import('@/views/Warehouse/Issue/form.vue'), meta: { title: '编辑领料单' } },
{ path: 'issue/view/:id', name: 'IssueView', component: () => import('@/views/Warehouse/Issue/form.vue'), meta: { title: '查看领料单' } }
]
}
```
---
## 3. 列表页 `index.vue`
遵循 WorkOrder/index.vue 模式:
- **搜索区**7 个字段 (issueCode, issueName, workorderCode, workstationName, status下拉, beginDate, endDate) + 搜索/重置按钮
- **工具栏**:新增(success) / 修改(primary) / 删除(danger) / 导出(warning) 四个按钮
- **表格**:复选框 + 11 列 (issueCode蓝色链接, issueName, workorderCode, taskCode, workstationName, clientName, issueDate, requiredTime, status标签, 操作列)
- **操作列**:根据 status 动态显隐 — 草稿显示:查看/编辑/删除/执行出库;已完成仅显示:查看
- **分页**el-paginationsizes=[10,20,50,100]
- **删除校验**:仅 PREPARE 状态允许,非草稿提示 "只能删除草稿状态的单据!"
- **执行出库**:调用 `checkQuantity` 校验 -> `executeIssue` -> 刷新列表
---
## 4. 表单页 `form.vue` (重点,三层数据)
这是本模块最复杂的部分,包含 **表头表单 + 领料行子表 + 出库明细子表 + 4个选择弹窗**
### 4.1 页面顶部操作栏
- 新增/编辑模式:保存 + 取消 + 执行出库(编辑模式) + 收起/展开
- 查看模式:新增 + 编辑(仅草稿) + 收起/展开
### 4.2 表头表单 (el-collapse + el-form)
- 4 列布局 (`el-col :span="6"`)
- 字段issueCode(必填), issueName(必填), 工单(选择弹窗), workorderCode(只读), 任务(选择), taskCode(只读), 工作站(选择), workstationCode/Name(只读), 客户(选择), clientCode/Name(只读), issueDate(日期), requiredTime(日期), status(标签), remark(textarea)
- 选择按钮通过 `el-input``#append` 插槽实现,与 WorkOrder 一致
### 4.3 领料行子表 (el-table, 可编辑)
- 数据源:`lineList: IssueLine[]`
- 列:序号, 物料编码(带选择按钮), 物料名称(只读), 规格型号(只读), 单位(只读), 领料数量(el-input-number), 批次号, 备注, 操作(编辑明细/删除)
- 「添加行」按钮push 空行到 lineList
- 行点击/「编辑明细」:设置 `selectedLineIndex`,展示该行的出库明细
- 保存流程:表头保存后,逐行调用 `createIssueLine` / `updateIssueLine`;删除行调用 `deleteIssueLine`
### 4.4 出库明细子表 (el-table, 可编辑)
- 仅当选中某领料行时显示
- 数据源:`detailList: IssueDetail[]` (按 lineId 过滤)
- 列:序号, 物料编码/名称(只读,从行带入), 仓库(el-select), 库区(el-select,联动), 库位(el-select,联动), 批次号, 出库数量(el-input-number), 备注, 操作(删除)
- 仓库/库区/库位**三级联动**:选择仓库 -> 加载库区 -> 选择库区 -> 加载库位
- 保存:调用 `createIssueDetail` / `updateIssueDetail` / `deleteIssueDetail`
### 4.5 选择弹窗4 个)
| 弹窗 | 数据来源 | 选择模式 | 回填字段 |
| ----- | ------------------------- | ----- | -------------------------------------------------------- |
| 选择工单 | `/mes/pro/workorder/list` | 单选 | workorderId, workorderCode |
| 选择物料 | `/mes/md/mditem/list` | 单选/多选 | itemId, itemCode, itemName, specification, unitOfMeasure |
| 选择客户 | `/mes/md/client/list` | 单选 | clientId, clientCode, clientName |
| 选择工作站 | workstation接口 | 单选 | workstationId, workstationCode, workstationName |
弹窗结构遵循 WorkOrder form.vue 的 `el-dialog` + 搜索区 + `el-table` + highlight-current-row + 确定/取消 模式。
### 4.6 数据加载流程(编辑/查看)
```mermaid
sequenceDiagram
participant Page as form.vue
participant API as API Layer
participant BE as Backend
Page->>API: getIssueHeaderDetail(id)
API->>BE: GET /mes/wm/issueheader/{id}
BE-->>Page: 表头数据
Page->>API: getIssueLineList(issueId)
API->>BE: GET /mes/wm/issueline/list?issueId=xx
BE-->>Page: 领料行列表
Page->>API: getIssueDetailList(issueId)
API->>BE: GET /mes/wm/issuedetail/list?issueId=xx
BE-->>Page: 出库明细列表
```
### 4.7 保存流程
1. 表单校验 (issueCode必填, issueName必填)
2. 新增:`createIssueHeader` -> 获取 issueId -> `router.replace` 到编辑页
3. 编辑:`updateIssueHeader` -> 成功提示
4. 领料行的增删改在保存表头后独立操作(行级 CRUD
5. 出库明细的增删改同样独立操作
### 4.8 执行出库流程
1. 前端校验:至少 1 条领料行,每行有明细数据
2. 调用 `checkQuantity(issueId)` 校验数量匹配
3. 调用 `executeIssue(issueId)` 执行出库
4. 成功后刷新页面数据status 变为 FINISHED
---
## 5. 关键实现要点
- **三级联动**:仓库 -> 库区 -> 库位,使用 watch 监听上级变化,清空下级选项并重新加载
- **行级编辑**领料行和出库明细均为表格内编辑inline edit非弹窗编辑
- **状态控制**:所有编辑操作受 `isView``formData.status` 双重控制FINISHED 状态只读
- **样式复用**:直接复用 WorkOrder 的 `.form-container`, `.page-header`, `.main-card`, `.section-header`, `.dialog-search` 等 CSS 类

View File

@@ -0,0 +1,150 @@
---
name: Production Plan MBOM Features
overview: Complete the production plan page to support re-running BOM calculation, canceling workshop dispatch, conditionally editing workshop/date based on dispatch status, and modifying supply method -- all on an approved production plan in view mode.
todos:
- id: backend-revoke-issue
content: Add PUT /erp/mp/mbom/revoke-issue/{mbomId} endpoint in MpMbomController, IMpMbomService, MpMbomServiceImpl
status: completed
- id: backend-bom-recalc
content: Fix MpPlanServiceImpl.bomCalculate to delete non-issued MBOMs before re-creating, preventing duplicates
status: completed
- id: frontend-api-revoke
content: Add revokeIssue(mbomId) function in erp-frontend-vue/src/api/mbom.ts
status: completed
- id: frontend-canEditMbom
content: Change canEditMbom computed to allow editing in view mode (remove !isView.value check)
status: completed
- id: frontend-bom-confirm
content: Add re-run confirmation dialog in handleBomCalculate when MBOMs already exist
status: completed
- id: frontend-revoke-confirm
content: Add 撤销下发 confirmation dialog in handleMbomIssueToggle and call revokeIssue API
status: completed
- id: frontend-issued-guards
content: Disable workshop/date editing when row is ISSUED with error messages
status: completed
- id: frontend-supply-success
content: Show 修改成功 message on supply type change
status: completed
isProject: false
---
# Complete Production Plan Page MBOM Features
## Current State
The production plan form (`form.vue`) already has partial support for BOM calculation, material list viewing, workshop dispatch, and supply method editing. However, several features are incomplete or have incorrect behavior:
- BOM calculation can be run but no confirmation when re-running (would create duplicates)
- Workshop dispatch toggle lacks confirmation for revoke ("撤销下发")
- No validation to prevent editing workshop/date when row is already issued
- `canEditMbom` is gated by `!isView.value`, blocking edits on the "查看" (view) page
- Backend has no dedicated revoke-issue endpoint
- Backend `bomCalculate` creates duplicate MBOMs on re-run
## Changes Required
### 1. Backend: Add revoke-issue endpoint and fix BOM re-calculation
**[MpMbomController.java](mom-backend/ktg-mes/src/main/java/com/ktg/mes/mp/controller/MpMbomController.java)** -- Add `PUT /erp/mp/mbom/revoke-issue/{mbomId}`:
- Validate MBOM exists and is in ISSUED state
- Call new `revokeIssue()` service method
- Clear `issueStatus` (set to null), keep `workshopId`/`workshopName`/`issueDate` so user can adjust them
**[IMpMbomService.java](mom-backend/ktg-mes/src/main/java/com/ktg/mes/mp/service/IMpMbomService.java)** -- Add interface method:
```java
public int revokeIssue(Long mbomId);
```
**[MpMbomServiceImpl.java](mom-backend/ktg-mes/src/main/java/com/ktg/mes/mp/service/impl/MpMbomServiceImpl.java)** -- Implement `revokeIssue`:
- Set `issueStatus = null`
- Update timestamp
**[MpPlanServiceImpl.java](mom-backend/ktg-mes/src/main/java/com/ktg/mes/mp/service/impl/MpPlanServiceImpl.java)** -- Fix `bomCalculate` for re-run:
- Before creating new MBOMs, find existing MBOMs for this plan
- Delete non-issued MBOMs (and their lines) to avoid duplicates
- Only create new MBOMs for plan lines that don't already have an issued MBOM
### 2. Frontend API: Add revoke-issue call
**[mbom.ts](erp-frontend-vue/src/api/mbom.ts)** -- Add:
```typescript
export function revokeIssue(mbomId: number): Promise<void> {
return request.put(`/erp/mp/mbom/revoke-issue/${mbomId}`)
}
```
### 3. Frontend: Update form.vue
**[form.vue](erp-frontend-vue/src/views/Production/PlanOrder/form.vue)** -- Main changes:
**(a) Allow MBOM editing in view mode** (line ~698):
- Change `canEditMbom` to remove `!isView.value` check:
```javascript
const canEditMbom = computed(() => {
const approved = formData.status === '审核' || formData.status === 'APPROVED'
const hasMbom = (formData.mbomList?.length ?? 0) > 0
return approved && hasMbom
})
```
**(b) BOM calculation with confirmation for re-run** (line ~714):
- In `handleBomCalculate()`, when `formData.mbomList` already has items, show `ElMessageBox.confirm('确认是否重新执行物料计算?', '警告', { type: 'warning' })` before proceeding
**(c) Issue toggle: add confirmation for revoke** (line ~802):
- In `handleMbomIssueToggle()`, when `checked === false` (turning OFF):
- Show `ElMessageBox.confirm('撤销下发', '警告', { type: 'warning' })` confirmation
- After confirmation, call `revokeIssue(id)` API instead of generic `saveMbomRow`
- Reload plan data after success
**(d) Workshop selector: block when issued** (template line ~304):
- Add `:disabled="row.issueStatus === 'ISSUED'"` to the workshop `el-select`
- In `handleMbomWorkshopChange()`, add early guard: if `row.issueStatus === 'ISSUED'`, show `ElMessage.error('下发状态下无法修改生产车间')` and return
**(e) Issue date picker: block when issued** (template line ~326):
- Add `:disabled="row.issueStatus === 'ISSUED'"` to the date `el-date-picker`
- In `handleMbomIssueDateChange()`, add early guard: if `row.issueStatus === 'ISSUED'`, show `ElMessage.error('下发状态下无法修改生产日期')` and return
**(f) Supply method: always editable** (template line ~277):
- Supply method select and "转委外" button remain editable regardless of issue status (current behavior matches this, no change needed in the select itself)
- But update `handleMbomSupplyTypeChange` to show success message "修改成功"
## Data Flow
```mermaid
flowchart TD
A[Approved_Plan] -->|"Click BOM计算"| B{Has existing MBOMs?}
B -->|No| C[Run BOM calculation]
B -->|Yes| D["Confirm: 确认是否重新执行物料计算?"]
D -->|OK| C
C --> E[Refresh plan data]
F[MBOM_Row_Not_Issued] -->|"Toggle ON"| G{Workshop selected?}
G -->|Yes| H[Call issueToWorkshop API]
G -->|No| I["Warning: 请先选择下发车间"]
J[MBOM_Row_Issued] -->|"Toggle OFF"| K["Confirm: 撤销下发"]
K -->|OK| L[Call revokeIssue API]
L --> E
J -->|"Edit workshop"| M["Error: 下发状态下无法修改生产车间"]
J -->|"Edit date"| N["Error: 下发状态下无法修改生产日期"]
F -->|"Edit workshop/date/supply"| O[Call updateMbom API]
O --> P["Success: 修改成功"]
```

View File

@@ -0,0 +1,124 @@
---
name: Purchase Order Pages
overview: Implement the Purchase Order (采购订单) module per the PRD, upgrading the existing skeletal frontend pages and filling backend gaps (detail-view query, import dialog API, supplier integration).
todos:
- id: backend-detail-view
content: Add selectPoOrderDetailList in PoOrderMapper.xml joining erp_po_order + erp_po_order_line for line-level detail view with filters (trackCode, itemCode, itemName, supplierName, date range). Add /list endpoint alias or param to return this.
status: completed
- id: backend-import-api
content: Add GET /erp/po/order/leadIn endpoint in PoOrderController that queries erp_mp_purchase (APPROVED, unpurchased qty > 0) with search by trackCode/itemCode/itemName, returning 10-column data for import dialog.
status: completed
- id: backend-date-params
content: Update PoOrderMapper.xml selectPoOrderList and selectPoOrderDocList to accept beginDate/endDate params (align with frontend naming).
status: completed
- id: frontend-supplier-api
content: Add poSupplier API functions in purchaseOrder.ts (or new file) calling /erp/po/supplier/list. Map PoSupplier fields (supplierName, contact1, tel, contact1Tel, enableFlag).
status: completed
- id: frontend-index-fix
content: "Fix index.vue detail view: replace row.lines?.[0]?.xxx with flat fields from the new detail-list query. Ensure date params align with backend."
status: completed
- id: frontend-form-header
content: "Rework form.vue header: 4-row x 5-col layout per PRD 4.2. Add collapse toggle, audit fields, status tags using PREPARE/APPROVED codes, businessStatus select, contractNo, contractFile upload placeholder."
status: completed
- id: frontend-form-supplier
content: "Rework supplier dialog in form.vue: use PoSupplier API, add 7 columns (序号/名称/电话/联系人/手机/状态/操作), search by name + contact, 快速添加 + 查询所有 buttons."
status: completed
- id: frontend-form-import
content: "Implement real import dialog in form.vue: call /erp/po/order/leadIn API, 10-column table per PRD 4.5, search fields (跟单编号/料品大类/物料编码/物料名称), 全选 button, confirm adds lines with itemId."
status: completed
- id: frontend-form-table
content: "Enhance material table: add show-summary for 合计 row (数量/金额/到货数量), auto-calc amount=qty*price, compute totalQuantity/totalAmount before save, add supplierCode to supplier selection."
status: completed
- id: frontend-form-buttons
content: "Add all mode-specific buttons: view mode (新增/编辑/审核/反审核/打印/操作/收起), edit mode (保存/撤回/审核/反审核/操作/收起/引入/新增物料), 上一条/下一条 navigation."
status: completed
isProject: false
---
# Purchase Order Page Development Plan
## Current State
The module has a working backend (CRUD, approve/unapprove, code generation, summary) and skeletal frontend pages. Key existing files:
- **Backend**: [PoOrderController.java](mom-backend/ktg-mes/src/main/java/com/ktg/mes/po/controller/PoOrderController.java), [PoOrderMapper.xml](mom-backend/ktg-mes/src/main/resources/mapper/po/PoOrderMapper.xml), [PoOrderLineMapper.xml](mom-backend/ktg-mes/src/main/resources/mapper/po/PoOrderLineMapper.xml), [PoSupplierController.java](mom-backend/ktg-mes/src/main/java/com/ktg/mes/po/controller/PoSupplierController.java)
- **Frontend**: [index.vue](erp-frontend-vue/src/views/Purchasing/Order/index.vue), [form.vue](erp-frontend-vue/src/views/Purchasing/Order/form.vue), [purchaseOrder.ts](erp-frontend-vue/src/api/purchaseOrder.ts), [supplier.ts](erp-frontend-vue/src/api/supplier.ts)
## Gaps to Fill
### Backend
1. **Detail-view query**: The PRD detail view is line-level (83 rows for 44 orders). Current `selectPoOrderList` returns order-level rows. Need a new mapper query `selectPoOrderDetailList` that joins `erp_po_order` with `erp_po_order_line` and supports filters: `trackCode`, `orderCode`, `supplierName`, `itemCode`, `itemName`, `beginDate`, `endDate`.
2. **Import dialog API (引入采购计划单明细)**: Need `GET /erp/po/order/leadIn` that queries `erp_mp_purchase` (status=APPROVED) with `purchaseQty - orderedQty > 0`, returning: planCode, salesOrderCode (trackCode), salesUserName, deliveryDate, itemId, itemCode, itemName, specification, unitName, needDate (demandDate), demandQty, orderedQty, unpurchasedQty. Support search by: trackCode, itemCode, itemName.
3. **Date filter params**: `selectPoOrderList` uses `params.beginOrderDate`/`params.endOrderDate` but frontend sends `beginDate`/`endDate`. Need to add support for both or align naming.
4. **Supplier list endpoint**: Backend already has `GET /erp/po/supplier/list` (at [PoSupplierController](mom-backend/ktg-mes/src/main/java/com/ktg/mes/po/controller/PoSupplierController.java)). Frontend currently calls `/mes/md/vendor` (MOM vendor table). For PO, should use `/erp/po/supplier`.
### Frontend
1. `**index.vue` detail view data model**: Currently accesses `row.lines?.[0]?.trackCode` but the list API returns flat orders without lines. After backend adds the line-level detail query, update the template to use flat fields directly (`row.trackCode`, `row.itemCode`, etc.).
2. `**form.vue` major rework** (the biggest task):
- **Status codes**: Use `PREPARE`/`APPROVED`/`CLOSED` instead of Chinese labels `开立`/`审核`
- **Header collapse**: Add toggle button and `v-show` for header form (pattern from [PurchasePlan/form.vue](erp-frontend-vue/src/views/Production/PurchasePlan/form.vue))
- **Full 4-row header layout** per PRD 4.2: add missing fields (审核员, 审核日期, 业务状态, 采购合同/上传, 用料需求 as read-only)
- **Supplier dialog**: Switch from `/mes/md/vendor` to `/erp/po/supplier` API; add columns for 序号, 电话, 手机号, 状态, 操作(选择); add search by name + contact person + 快速添加 + 查询所有
- **Import dialog**: Replace hardcoded data with real API call to `GET /erp/po/order/leadIn`; add 10-column table per PRD 4.5; add search fields (跟单编号, 料品大类, 物料编码, 物料名称); add 全选 button
- **Material table summary row**: Add `show-summary` with sum of 数量, 金额, 到货数量
- **Amount auto-calculation**: `amount = quantity * unitPrice` on change, update `totalQuantity` and `totalAmount` on header before save
- **Buttons per mode**: view=[新增/编辑/审核/反审核/打印/操作/收起], edit=[保存/撤回/审核/反审核/操作/收起/引入/新增物料], add=[保存/取消/审核/反审核/收起/引入/新增物料]
- **上一条/下一条** navigation (view/edit mode)
- **撤回** button: reload saved data from server
- **打印** button: `window.print()` or print dialog
- **Compute totals** before save: `totalQuantity = sum(line.quantity)`, `totalAmount = sum(line.amount)`
3. `**purchaseOrder.ts` API additions**: Add `getImportPlanDetails(params)`, `getPoSupplierList(params)` functions.
## Architecture
```mermaid
flowchart TD
subgraph fe [Frontend]
IndexVue["index.vue\n(list: detail + document views)"]
FormVue["form.vue\n(add/edit/view)"]
ApiTs["purchaseOrder.ts"]
SupplierApi["supplier API"]
end
subgraph be [Backend]
Controller["PoOrderController"]
SupplierCtrl["PoSupplierController"]
OrderSvc["PoOrderService"]
PurchaseSvc["MpPurchaseService"]
OrderMapper["PoOrderMapper.xml"]
LineMapper["PoOrderLineMapper.xml"]
end
subgraph db [Database]
PoOrder["erp_po_order"]
PoLine["erp_po_order_line"]
MpPurchase["erp_mp_purchase"]
PoSupplier["erp_po_supplier"]
end
IndexVue --> ApiTs
FormVue --> ApiTs
FormVue --> SupplierApi
ApiTs --> Controller
SupplierApi --> SupplierCtrl
Controller --> OrderSvc
Controller --> PurchaseSvc
OrderSvc --> OrderMapper
OrderSvc --> LineMapper
OrderMapper --> PoOrder
LineMapper --> PoLine
PurchaseSvc --> MpPurchase
SupplierCtrl --> PoSupplier
```
## Key Implementation Notes
- The `erp_po_order` + `erp_po_order_line` is a proper 1:N header/line model (unlike `erp_mp_purchase` which is flat). Backend already handles insert/update with lines in the controller.
- Supplier selection dialog in the PRD references `erp_po_supplier` (not `md_vendor`). The controller at `/erp/po/supplier` is already implemented. Frontend needs a new API wrapper or reuse existing supplier.ts with path change.
- For the import dialog, we query `erp_mp_purchase` (approved plans) and map fields to the import dialog's 10 columns.
- Pattern reference: [PurchasePlan/form.vue](erp-frontend-vue/src/views/Production/PurchasePlan/form.vue) for header collapse, import dialog, material table patterns.

View File

@@ -0,0 +1,572 @@
---
name: Universal Document Print
overview: 设计并实现跨项目的通用单据打印框架,覆盖 erp-frontend-vue (Vue 3) 和 mom-backend-ui (Vue 2) 两个前端项目中所有单据类型的打印需求,采用配置驱动方式,一套设计思路适配全部单据。
todos:
- id: install-deps-vue3
content: "erp-frontend-vue: 安装 qrcode + @types/qrcode"
status: completed
- id: install-deps-vue2
content: "mom-backend-ui: 安装 qrcode已有 vue-plugin-hiprint 用于标签,文档打印需另行处理)"
status: pending
- id: print-types
content: 创建 PrintConfig 类型/接口定义(两项目各一份,结构一致)
status: completed
- id: qrcode-vue3
content: "erp-frontend-vue: 创建 src/components/print/QrCode.vue"
status: completed
- id: print-dialog-vue3
content: "erp-frontend-vue: 创建 src/components/print/PrintDialog.vue@media print 样式)"
status: completed
- id: qrcode-vue2
content: "mom-backend-ui: 创建 src/components/PrintDoc/QrCode.vueVue 2 版)"
status: pending
- id: print-dialog-vue2
content: "mom-backend-ui: 创建 src/components/PrintDoc/PrintDialog.vueVue 2 版,含 @media print 样式)"
status: pending
- id: task-api
content: "erp-frontend-vue: 在 workOrder.ts 中添加 ProTask 类型和 getTaskListByWorkorder API"
status: completed
- id: integrate-workorder-vue3
content: "erp-frontend-vue: 生产工单 form.vue 集成打印"
status: completed
- id: integrate-sales-vue3
content: "erp-frontend-vue: 销售订单 form.vue 集成打印"
status: completed
- id: integrate-purchase-vue3
content: "erp-frontend-vue: 采购订单 form.vue 集成打印"
status: completed
- id: integrate-issue-vue3
content: "erp-frontend-vue: 生产领料单 form.vue 集成打印"
status: completed
- id: integrate-arrival-vue2
content: "mom-backend-ui: 到货通知单 index.vue 集成打印"
status: pending
- id: integrate-itemrecpt-vue2
content: "mom-backend-ui: 物料入库单 index.vue 集成打印"
status: pending
- id: integrate-productsales-vue2
content: "mom-backend-ui: 销售出库单 index.vue 集成打印"
status: pending
- id: integrate-remaining-vue2
content: "mom-backend-ui: 其余仓库单据(退货/转移/杂项等)逐步集成打印"
status: pending
isProject: false
---
# 通用单据打印框架(跨项目)
## 现状分析
### erp-frontend-vueVue 3 + Element Plus
- `handlePrint()` 要么仅调 `window.print()`(生产工单、采购订单),要么是占位符(销售订单等)
-`@media print` 样式、无 QR 码库、无打印组件
- 包含单据:销售订单、采购订单、生产工单、生产领料单、采购到货单(表单未完成)
### mom-backend-uiVue 2 + Element UI
- 已有 `vue-plugin-hiprint` 用于**条码标签**打印(物料/仓库/工位标签),但**无单据格式打印**
- `handleHiPrint` 仅在 detail 页做标签打印,不是单据表单打印
- 包含大量仓库单据模块:到货通知、入库单(4种)、领料单(3种)、出库单(2种)、退货单(3种)、转移单、装箱单、备料通知等
### 两项目共同点
所有单据结构高度一致:**表头字段** + **明细行列表**,适合用统一的配置驱动方案。
## 架构设计
### 核心思路:配置驱动 + 双项目适配
```mermaid
graph TB
subgraph config ["PrintConfig 配置接口(结构一致)"]
fields["headerFields: 表头字段数组"]
cols["columns: 明细列定义"]
data["data: 明细行数据"]
meta["title / qrCode / footer"]
end
subgraph vue3 ["erp-frontend-vue (Vue 3)"]
pd3["PrintDialog.vue"]
qr3["QrCode.vue"]
pages3["各单据 form.vue"]
end
subgraph vue2 ["mom-backend-ui (Vue 2)"]
pd2["PrintDialog.vue"]
qr2["QrCode.vue"]
pages2["各单据 index.vue"]
end
pages3 -->|"构建 config"| pd3
pages2 -->|"构建 config"| pd2
pd3 --> qr3
pd2 --> qr2
config -.->|"同一结构"| pd3
config -.->|"同一结构"| pd2
```
### PrintConfig 接口定义
两个项目各自维护一份Vue 3 用 TypeScriptVue 2 用 JSDoc结构完全一致
```typescript
/** 表头字段 */
interface PrintHeaderField {
label: string // "单据编码"
value: string | number // "SCDD000001"
span?: number // 占列数,默认 1共 4 列一行)
}
/** 明细表列 */
interface PrintColumn {
prop: string // 数据字段名
label: string // 列标题
width?: string // 列宽
align?: 'left' | 'center' | 'right'
type?: 'text' | 'index' | 'qrcode' | 'amount'
qrCodeProp?: string // type=qrcode 时的编码内容字段
formatter?: (row: any, index: number) => string
}
/** 合计行 */
interface PrintSummary {
label: string
value: string | number
}
/** 完整打印配置 */
interface PrintConfig {
systemName?: string // 默认 "升阳云ERP"
title: string // "销售订单" | "到货通知单" | ...
subtitle?: string // "加工车间" 等
qrCodeValue?: string // 右上角二维码内容
headerFields: PrintHeaderField[] // 4 列网格,自动换行
columns: PrintColumn[] // 明细表列
data: any[] // 明细表数据
summaries?: PrintSummary[] // 合计行(可选)
footer: {
creator?: string // 制单人
approver?: string // 审核人
}
}
```
### 打印页面统一布局
```
+------------------------------------------------------------------+
| 升阳云ERP [QR 码] |
| {title} - {subtitle} |
| |
| {label}: {value} {label}: {value} {label}: {value} {label}:|
| {label}: {value} {label}: {value} {label}: {value} {label}:|
| |
| +----+----------+----------+------+------+----------+------+ |
| | 序号| 列1 | 列2 | 列3 | 列4 | 列5 | 列6 | |
| +----+----------+----------+------+------+----------+------+ |
| | 1 | ... | ... | ... | ... | [QR码] | ... | |
| +----+----------+----------+------+------+----------+------+ |
| |
| 制单人: xxx 审核人: xxx 打印日期: 2025-xx-xx |
+------------------------------------------------------------------+
```
## 实现步骤
### 第一步:依赖安装
**erp-frontend-vue:**
```bash
cd erp-frontend-vue && npm install qrcode && npm install -D @types/qrcode
```
**mom-backend-ui:**
```bash
cd mom-backend-ui && npm install qrcode
```
### 第二步:公共组件开发
#### Vue 3 版erp-frontend-vue
新建目录 `src/components/print/`,包含 3 个文件:
| 文件 | 说明 |
| --------------------------------------------------------------------------------------------- | -------------------------- |
| [src/components/print/types.ts](erp-frontend-vue/src/components/print/types.ts) | PrintConfig 等类型定义 |
| [src/components/print/QrCode.vue](erp-frontend-vue/src/components/print/QrCode.vue) | QR 码组件Props: value, size |
| [src/components/print/PrintDialog.vue](erp-frontend-vue/src/components/print/PrintDialog.vue) | 通用打印对话框 |
**QrCode.vue** — 使用 `qrcode.toDataURL()` 生成 base64 图片,渲染 `<img>` 标签。
**PrintDialog.vue** — 核心组件:
- Props: `v-model:visible``config: PrintConfig`
- `el-dialog`fullscreen包裹打印预览
- 对话框 header 有「打印」「关闭」按钮
- 打印内容区使用纯 HTML table + CSS Grid不依赖 Element Plus确保打印输出干净
- 组件内嵌 `@media print` 样式,隐藏对话框 header/footer仅保留 `.print-content`
#### Vue 2 版mom-backend-ui
新建目录 `src/components/PrintDoc/`,包含 2 个文件:
| 文件 | 说明 |
| ------------------------------------------------------------------------------------------------- | --------------------------------------- |
| [src/components/PrintDoc/QrCode.vue](mom-backend-ui/src/components/PrintDoc/QrCode.vue) | QR 码组件Vue 2 语法) |
| [src/components/PrintDoc/PrintDialog.vue](mom-backend-ui/src/components/PrintDoc/PrintDialog.vue) | 通用打印对话框Vue 2 + Element UI `el-dialog` |
两个版本的**布局 HTML 和 CSS 完全一致**,仅框架语法不同:
- Vue 3: `<script setup>` + `defineProps` + `v-model:visible`
- Vue 2: `export default` + `props` + `.sync` 修饰符
### 第三步:打印专用 CSS两项目通用
嵌入在 PrintDialog 组件内(或独立 CSS 文件),核心规则:
```css
@media print {
body > *:not(.el-overlay):not(.v-modal) { display: none !important; }
.el-overlay, .v-modal { position: static !important; overflow: visible !important; }
.el-dialog__wrapper { position: static !important; overflow: visible !important; }
.el-dialog { box-shadow: none !important; border: none !important;
margin: 0 !important; width: 100% !important; }
.el-dialog__header, .el-dialog__footer,
.print-dialog-actions { display: none !important; }
.print-content { padding: 8mm 10mm; margin: 0; }
.print-content table { page-break-inside: auto; }
.print-content tr { page-break-inside: avoid; }
}
```
### 第四步:各单据集成
每个单据页面的 `handlePrint()` 只需:
1. 构建 `PrintConfig` 对象(映射该单据的字段)
2. 设置 `showPrintDialog = true`
---
## 全部单据配置清单
### A. erp-frontend-vue 项目Vue 3
#### A1. 生产工单
**页面**: [src/views/Production/WorkOrder/form.vue](erp-frontend-vue/src/views/Production/WorkOrder/form.vue)
**需新增 API**: `getTaskListByWorkorder(workorderId)` -> `GET /mes/pro/protask/list` (添加到 [src/api/workOrder.ts](erp-frontend-vue/src/api/workOrder.ts)
**表头字段headerFields**
- 单据编码 `workorderCode` / 跟单号 `salesOrderCode` / 物料编码 `productCode` / 工艺路线 `routeName`
- 单据日期 `orderDate` / 操作员 `operatorName` / 物料名称 `productName + productSpc` / 生产线 `productionLine`
- 单据状态 `status` / 订单交期 `deliveryDate` / 计量单位 `unitName` / 生产日期 `productionDate`
- 业务状态 `businessStatus` / 需求日期 `requestDate` / 生产数量 `quantity` / 备注 `remark`
**明细列(工序,来自 ProTask**
- 序号(index) / 工序编码 `processCode` / 工序名称 `processName` / 应报数量 `quantity` / 计件方式(固定"个人") / 扫码报工(qrcode) / 备注
**页脚**: 制单人 `createBy` / 审核人 `approverName`
---
#### A2. 销售订单
**页面**: [src/views/Sales/Order/form.vue](erp-frontend-vue/src/views/Sales/Order/form.vue)
**表头字段:**
- 单据编码 `orderCode` / 单据日期 `orderDate` / 单据状态 `orderStatus` / 业务类型 `bizType`
- 客户名称 `clientName` / 销售人员 `salesmanName` / 销售部门 `deptName` / 合同号 `contractNo`
- 交付日期 `deliveryDate` / 付款条件 `paymentTerms` / 收货人 `receiver` / 收货电话 `receiverPhone`
- 收货地址 `receiverAddress`(span:2) / 备注 `remark`(span:2)
**明细列(物料行,来自 `lines`**
- 序号 / 物料编码 `itemCode` / 物料名称 `itemName` / 型号规格 `specification` / 主计量 `unitOfMeasure` / 数量 `quantity` / 单价 `unitPrice` / 金额 `amount` / 质量要求 `qualityReq` / 备注 `remark`
**合计**: 总金额 `totalAmount`
**页脚**: 制单人 `createBy` / 审核人 `auditorName`
---
#### A3. 采购订单
**页面**: [src/views/Purchasing/Order/form.vue](erp-frontend-vue/src/views/Purchasing/Order/form.vue)
**表头字段:**
- 单据编码 `orderCode` / 单据日期 `orderDate` / 单据状态 `status` / 业务类型 `businessType`
- 业务状态 `businessStatus` / 供方 `supplierName` / 采购部门 `deptName` / 采购人员 `userName`
- 到货日期 `deliveryDate` / 合同号 `contractNo` / 用料需求 `materialNeed` / 备注 `remark`
**明细列(采购行,来自 `lines`**
- 序号 / 跟单编号 `trackCode` / 计划单号 `planCode` / 物料编码 `itemCode` / 物料名称 `itemName` / 型号规格 `specification` / 主计量 `unitName` / 数量 `quantity` / 单价 `unitPrice` / 金额 `amount` / 采购说明 `remark`
**合计**: 总数量 `totalQuantity` / 总金额 `totalAmount`
**页脚**: 制单人 `operatorName` / 审核人 `approverName`
---
#### A4. 生产领料单
**页面**: [src/views/Warehouse/Issue/form.vue](erp-frontend-vue/src/views/Warehouse/Issue/form.vue)(需新增打印按钮)
**表头字段:**
- 单据编码 `issueCode` / 领料日期 `issueDate` / 单据状态 `status` / 工单编码 `workorderCode`
- 工作站 `workstationName` / 客户名称 `clientName` / 需求时间 `requiredTime` / 备注 `remark`
**明细列(领料行):**
- 序号 / 物料编码 `itemCode` / 物料名称 `itemName` / 规格型号 `specification` / 计量单位 `unitName` / 领料数量 `quantityIssued` / 批次号 `batchCode` / 备注 `remark`
**页脚**: 制单人 `createBy`
---
### B. mom-backend-ui 项目Vue 2
以下单据在老项目中,均无单据打印功能(仅部分有标签打印)。统一使用 `PrintDialog` 组件集成。
#### B1. 到货通知单
**页面**: [src/views/mes/wm/arrivalnotice/index.vue](mom-backend-ui/src/views/mes/wm/arrivalnotice/index.vue) + [line.vue](mom-backend-ui/src/views/mes/wm/arrivalnotice/line.vue)
**表头字段:**
- 通知单编号 `noticeCode` / 通知单名称 `noticeName` / 采购订单号 `poCode` / 到货日期 `arrivalDate`
- 供应商 `vendorName` / 联系人 `contact` / 联系方式 `tel` / 单据状态 `status`
- 备注 `remark`(span:3)
**明细列(到货行):**
- 序号 / 物料编码 `itemCode` / 物料名称 `itemName` / 规格型号 `specification` / 单位 `unitName` / 到货数量 `quantityArrival` / 是否检验 `iqcCheck` / 合格数量 `quantityQuanlified` / 检验单号 `iqcCode` / 备注 `remark`
**页脚**: 制单人 `createBy`
---
#### B2. 物料入库单(采购入库)
**页面**: [src/views/mes/wm/itemrecpt/index.vue](mom-backend-ui/src/views/mes/wm/itemrecpt/index.vue) + [line.vue](mom-backend-ui/src/views/mes/wm/itemrecpt/line.vue)
**表头字段:**
- 入库单编号 `recptCode` / 入库单名称 `recptName` / 入库日期 `recptDate` / 单据状态 `status`
- 到货通知单 `noticeCode` / 采购订单号 `poCode` / 供应商 `vendorName` / 备注 `remark`
**明细列(入库行):**
- 序号 / 物料编码 `itemCode` / 物料名称 `itemName` / 规格型号 `specification` / 单位 `unitName` / 入库数量 `quantityRecived` / 批次号 `batchCode`
**页脚**: 制单人 `createBy`
---
#### B3. 产品入库单
**页面**: [src/views/mes/wm/productrecpt/](mom-backend-ui/src/views/mes/wm/productrecpt/)
**表头字段**: 入库单编号、名称、工单编码、入库日期、状态、备注
**明细列**: 产品编码、产品名称、规格、单位、入库数量、批次号
---
#### B4. 外协入库单
**页面**: [src/views/mes/wm/outsourcerecpt/](mom-backend-ui/src/views/mes/wm/outsourcerecpt/)
**表头**: 入库单编号、名称、外协工单号、入库日期、状态、备注
**明细**: 物料编码、物料名称、规格、单位、入库数量、批次号
---
#### B5. 销售出库单
**页面**: [src/views/mes/wm/productsales/index.vue](mom-backend-ui/src/views/mes/wm/productsales/index.vue) + [line.vue](mom-backend-ui/src/views/mes/wm/productsales/line.vue)
**表头字段:**
- 出库单编号 `salesCode` / 出库单名称 `salesName` / 发货通知单 `noticeCode` / 销售订单 `soCode`
- 客户编码 `clientCode` / 客户名称 `clientName` / 出库日期 `salesDate` / 单据状态 `status`
- 收货人 `recipient` / 联系方式 `tel` / 承运商 `carrier` / 运输单号 `shippingNumber`
- 收货地址 `address`(span:2) / 备注 `remark`(span:2)
**明细列(出库行):**
- 序号 / 产品编码 `itemCode` / 产品名称 `itemName` / 规格型号 `specification` / 单位 `unitName` / 出库数量 `quantitySales` / 批次号 `batchCode` / 是否检验 `oqcCheck` / 备注 `remark`
**页脚**: 制单人 `createBy`
---
#### B6. 发货通知单
**页面**: [src/views/mes/wm/salesnotice/](mom-backend-ui/src/views/mes/wm/salesnotice/)
**表头**: 通知单编号、销售订单号、客户名称、发货日期、收货人、联系方式、地址、承运商、状态
**明细**: 产品编码、产品名称、规格、单位、发货数量、批次号
---
#### B7. 供应商退货单
**页面**: [src/views/mes/wm/rtvendor/index.vue](mom-backend-ui/src/views/mes/wm/rtvendor/index.vue) + [line.vue](mom-backend-ui/src/views/mes/wm/rtvendor/line.vue)
**表头字段:**
- 退货单编号 `rtCode` / 退货单名称 `rtName` / 采购订单 `poCode` / 退货日期 `rtDate`
- 供应商 `vendorName` / 退货原因 `rtReason` / 运单号 `transportCode` / 单据状态 `status`
- 备注 `remark`(span:3)
**明细列:**
- 序号 / 物料编码 `itemCode` / 物料名称 `itemName` / 规格型号 `specification` / 单位 `unitName` / 退货数量 `quantityRted` / 批次号 `batchCode` / 备注 `remark`
---
#### B8. 销售退货单
**页面**: [src/views/mes/wm/rtsales/](mom-backend-ui/src/views/mes/wm/rtsales/)
**表头**: 退货单编号、销售订单号、客户名称、退货日期、状态
**明细**: 产品编码、产品名称、规格、单位、退货数量、批次号
---
#### B9. 生产退料单
**页面**: [src/views/mes/wm/rtissue/](mom-backend-ui/src/views/mes/wm/rtissue/)
**表头**: 退料单编号、工单编码、退料日期、状态
**明细**: 物料编码、物料名称、规格、单位、退料数量、批次号
---
#### B10. 生产领料单
**页面**: [src/views/mes/wm/issue/index.vue](mom-backend-ui/src/views/mes/wm/issue/index.vue) + [line.vue](mom-backend-ui/src/views/mes/wm/issue/line.vue)
**表头**: 领料单编号、领料单名称、工单编码、工作站、领料日期、状态
**明细**: 物料编码、物料名称、规格、单位、领料数量、备注
---
#### B11. 外协领料单
**页面**: [src/views/mes/wm/outsourceissue/](mom-backend-ui/src/views/mes/wm/outsourceissue/)
**表头**: 领料单编号、外协工单号、领料日期、状态
**明细**: 物料编码、物料名称、规格、单位、领料数量
---
#### B12. 转移单
**页面**: [src/views/mes/wm/transfer/index.vue](mom-backend-ui/src/views/mes/wm/transfer/index.vue)
**表头字段:**
- 转移单编号 `transferCode` / 转移单名称 `transferName` / 转移类型 `transferType` / 转移日期 `transferDate`
- 是否配送 `deliveryFlag` / 收货人 `recipient` / 联系方式 `tel` / 单据状态 `status`
- 承运商 `carrier` / 运输单号 `shippingNumber` / 目的地 `destination` / 备注 `remark`
**明细**: 物料编码、物料名称、规格、单位、转移数量、批次号
---
#### B13. 杂项入库单 / 杂项出库单 / 备料通知单 / 装箱单
**页面**: 分别位于 `mes/wm/miscrecpt/``mes/wm/miscissue/``mes/wm/mrnotice/``mes/wm/package/`
结构与上述单据一致,表头字段略有不同,明细均为物料行。集成方式相同:构建 `PrintConfig` 即可。
---
## 实施优先级
### Phase 1 — 公共组件 + 核心单据(优先)
1. 安装依赖(两个项目)
2. 创建公共打印组件Vue 3 版 + Vue 2 版)
3. erp-frontend-vue: 生产工单、销售订单、采购订单集成打印
4. mom-backend-ui: 到货通知单、物料入库单集成打印
### Phase 2 — 仓库出入库单据
1. erp-frontend-vue: 生产领料单集成打印
2. mom-backend-ui: 销售出库单、发货通知单、生产领料单集成打印
### Phase 3 — 退货/转移/其余单据
1. mom-backend-ui: 供应商退货单、销售退货单、生产退料单
2. mom-backend-ui: 转移单、外协入库/领料、杂项入库/出库、备料通知、装箱单
---
## 文件变更总览
### erp-frontend-vue新增 3 文件 + 修改 5 文件)
**新增:**
- `src/components/print/types.ts` — PrintConfig 类型定义
- `src/components/print/QrCode.vue` — QR 码组件
- `src/components/print/PrintDialog.vue` — 通用打印对话框
**修改:**
- `src/api/workOrder.ts` — 添加 ProTask 类型和 API
- `src/views/Production/WorkOrder/form.vue` — 集成打印
- `src/views/Sales/Order/form.vue` — 集成打印
- `src/views/Purchasing/Order/form.vue` — 集成打印
- `src/views/Warehouse/Issue/form.vue` — 添加打印按钮 + 集成打印
### mom-backend-ui新增 2 文件 + 修改 N 个单据页面)
**新增:**
- `src/components/PrintDoc/QrCode.vue` — QR 码组件Vue 2
- `src/components/PrintDoc/PrintDialog.vue` — 通用打印对话框Vue 2
**修改Phase 1-3 逐步):**
- `src/views/mes/wm/arrivalnotice/index.vue` — 到货通知单
- `src/views/mes/wm/itemrecpt/index.vue` — 物料入库单
- `src/views/mes/wm/productsales/index.vue` — 销售出库单
- `src/views/mes/wm/salesnotice/index.vue` — 发货通知单
- `src/views/mes/wm/issue/index.vue` — 生产领料单
- `src/views/mes/wm/rtvendor/index.vue` — 供应商退货单
- `src/views/mes/wm/rtsales/index.vue` — 销售退货单
- `src/views/mes/wm/rtissue/index.vue` — 生产退料单
- `src/views/mes/wm/transfer/index.vue` — 转移单
- 其余仓库单据页面...
**安装依赖:**
- erp-frontend-vue: `qrcode` + `@types/qrcode`
- mom-backend-ui: `qrcode`
## 扩展性说明
新增任何单据的打印,不论在哪个项目中,只需:
1. 在该单据页面中引入 `PrintDialog` 组件
2. 构建 `PrintConfig` 对象(映射表头字段 + 配置明细列 + 提供行数据)
3. 设置 `showPrintDialog = true`
无需修改任何公共打印组件。

View File

@@ -0,0 +1,341 @@
---
name: 修复Layout菜单操作失效
overview: 修复 Vue 2 到 Vue 3 迁移导致的 layout 菜单折叠/展开/关闭失效问题,根本原因是使用了 Vue 2 的 beforeDestroy 生命周期钩子,需要全部替换为 Vue 3 的 beforeUnmount
todos:
- id: fix-resize-handler
content: "修复 ResizeHandler.js: beforeDestroy → beforeUnmount"
status: completed
- id: fix-topnav
content: "修复 TopNav/index.vue: beforeDestroy → beforeUnmount"
status: completed
- id: fix-screenfull
content: "修复 Screenfull/index.vue: beforeDestroy → beforeUnmount"
status: completed
- id: fix-rightpanel
content: "修复 RightPanel/index.vue: beforeDestroy → beforeUnmount"
status: completed
- id: fix-editor-countto
content: "修复 Editor 和 CountTo 组件: beforeDestroy → beforeUnmount"
status: completed
- id: fix-chart-components
content: "修复所有图表组件和 mixins: beforeDestroy → beforeUnmount"
status: completed
- id: verify-layout
content: 验证侧边栏、顶部菜单、全屏、右侧面板功能
status: completed
isProject: false
---
# 修复 Layout 菜单操作失效问题
## 问题根源
Vue 3 中,生命周期钩子名称发生了变化:
- `beforeDestroy``beforeUnmount`
- `destroyed``unmounted`
当前项目使用了 `@vue/compat` (Vue 3 兼容模式),但这些组件仍在使用 Vue 2 的生命周期钩子。这导致组件销毁时的清理代码(移除事件监听器)没有执行,从而导致:
1. **侧边栏折叠/展开失效** - `[ResizeHandler.js](mom-backend-ui/src/layout/mixin/ResizeHandler.js)` 中的 resize 监听器没有正确清理
2. **顶部菜单操作失效** - `[TopNav/index.vue](mom-backend-ui/src/components/TopNav/index.vue)` 中的 resize 监听器问题
3. **右侧面板关闭失效** - `[RightPanel/index.vue](mom-backend-ui/src/components/RightPanel/index.vue)` 中的 click 监听器问题
4. **全屏功能失效** - `[Screenfull/index.vue](mom-backend-ui/src/components/Screenfull/index.vue)` 中的监听器问题
## 影响范围
共 13 个文件使用了 `beforeDestroy`
### 核心 Layout 相关(优先级 P0
1. `[src/layout/mixin/ResizeHandler.js](mom-backend-ui/src/layout/mixin/ResizeHandler.js)` - 控制侧边栏响应式
2. `[src/components/TopNav/index.vue](mom-backend-ui/src/components/TopNav/index.vue)` - 顶部菜单
3. `[src/components/Screenfull/index.vue](mom-backend-ui/src/components/Screenfull/index.vue)` - 全屏功能
4. `[src/components/RightPanel/index.vue](mom-backend-ui/src/components/RightPanel/index.vue)` - 右侧面板
### 其他组件(优先级 P1
1. `[src/components/Editor/index.vue](mom-backend-ui/src/components/Editor/index.vue)` - 富文本编辑器
2. `[src/components/CountTo/index.vue](mom-backend-ui/src/components/CountTo/index.vue)` - 数字动画
### 图表组件(优先级 P2
1. `src/views/dashboard/BarChart.vue`
2. `src/views/dashboard/LineChart.vue`
3. `src/views/dashboard/PieChart.vue`
4. `src/views/dashboard/RaddarChart.vue`
5. `src/views/mes/report/chart/chart.vue`
6. `src/views/mes/report/chart/mixins/resize.js`
7. `src/views/dashboard/mixins/resize.js`
## 修复方案
### 方案:批量替换生命周期钩子
所有文件中的 `beforeDestroy` 直接替换为 `beforeUnmount`
### 具体修改
#### 1. ResizeHandler Mixin
**文件**: `[src/layout/mixin/ResizeHandler.js](mom-backend-ui/src/layout/mixin/ResizeHandler.js)`
**第 17-19 行**:
```javascript
// 修复前
beforeDestroy() {
window.removeEventListener('resize', this.$_resizeHandler)
},
// 修复后
beforeUnmount() {
window.removeEventListener('resize', this.$_resizeHandler)
},
```
**影响**: 修复侧边栏折叠/展开功能
---
#### 2. TopNav 组件
**文件**: `[src/components/TopNav/index.vue](mom-backend-ui/src/components/TopNav/index.vue)`
**第 107-109 行**:
```javascript
// 修复前
beforeDestroy() {
window.removeEventListener('resize', this.setVisibleNumber)
},
// 修复后
beforeUnmount() {
window.removeEventListener('resize', this.setVisibleNumber)
},
```
**影响**: 修复顶部菜单响应式
---
#### 3. Screenfull 组件
**文件**: `[src/components/Screenfull/index.vue](mom-backend-ui/src/components/Screenfull/index.vue)`
**第 20-22 行**:
```javascript
// 修复前
beforeDestroy() {
this.destroy()
},
// 修复后
beforeUnmount() {
this.destroy()
},
```
**影响**: 修复全屏功能
---
#### 4. RightPanel 组件
**文件**: `[src/components/RightPanel/index.vue](mom-backend-ui/src/components/RightPanel/index.vue)`
**第 59-62 行**:
```javascript
// 修复前
beforeDestroy() {
const elx = this.$refs.rightPanel
elx.remove()
},
// 修复后
beforeUnmount() {
const elx = this.$refs.rightPanel
elx.remove()
},
```
**影响**: 修复右侧面板关闭功能
---
#### 5-6. Editor 和 CountTo 组件
**文件**:
- `src/components/Editor/index.vue`
- `src/components/CountTo/index.vue`
**修改**: `beforeDestroy``beforeUnmount`
---
#### 7-13. 图表组件和 Mixins
**文件**:
- `src/views/dashboard/BarChart.vue`
- `src/views/dashboard/LineChart.vue`
- `src/views/dashboard/PieChart.vue`
- `src/views/dashboard/RaddarChart.vue`
- `src/views/mes/report/chart/chart.vue`
- `src/views/mes/report/chart/mixins/resize.js`
- `src/views/dashboard/mixins/resize.js`
**修改**: `beforeDestroy``beforeUnmount`
**影响**: 修复图表组件的内存泄漏问题
## 验证方法
### 测试 1: 侧边栏折叠/展开
1. 打开系统
2. 点击左上角的 hamburger 图标(三条横线)
3. 验证侧边栏正常折叠/展开
4. 调整浏览器窗口大小
5. 验证侧边栏在移动端自动收起
**预期结果**: 所有操作正常响应
---
### 测试 2: 顶部菜单
1. 启用顶部菜单模式(在布局设置中)
2. 点击顶部菜单项
3. 验证菜单切换正常
4. 调整浏览器窗口大小
5. 验证菜单项自动折叠到"更多菜单"
**预期结果**: 菜单操作正常
---
### 测试 3: 全屏功能
1. 点击顶部工具栏的全屏图标
2. 验证进入全屏
3. 再次点击退出全屏
4. 验证图标状态正确切换
**预期结果**: 全屏功能正常
---
### 测试 4: 右侧面板
1. 点击顶部的"布局设置"
2. 验证右侧面板打开
3. 点击面板外部区域
4. 验证面板自动关闭
**预期结果**: 面板开关正常
---
### 测试 5: 控制台检查
打开浏览器控制台,执行以下检查:
1. 切换不同页面
2. 确认没有 "beforeDestroy is deprecated" 警告
3. 确认没有内存泄漏警告
4. 确认事件监听器正确添加和移除
## Vue 3 生命周期对照表
| Vue 2 | Vue 3 | 说明 |
| --------------- | --------------- | -------- |
| `beforeCreate` | `beforeCreate` | 无变化 |
| `created` | `created` | 无变化 |
| `beforeMount` | `beforeMount` | 无变化 |
| `mounted` | `mounted` | 无变化 |
| `beforeUpdate` | `beforeUpdate` | 无变化 |
| `updated` | `updated` | 无变化 |
| `beforeDestroy` | `beforeUnmount` | **已重命名** |
| `destroyed` | `unmounted` | **已重命名** |
| `activated` | `activated` | 无变化 |
| `deactivated` | `deactivated` | 无变化 |
| `errorCaptured` | `errorCaptured` | 无变化 |
## 技术要点
### 为什么需要修复
1. **事件监听器泄漏**: `beforeDestroy` 未执行导致 `removeEventListener` 没有调用
2. **内存泄漏**: 未清理的监听器持续占用内存
3. **功能失效**: 新的事件监听器无法正常工作
4. **Vue 3 兼容性**: `@vue/compat` 不完全支持 Vue 2 语法
### 影响分析
```mermaid
graph TD
A[组件挂载] --> B[添加事件监听器]
B --> C[组件使用中]
C --> D[组件卸载]
D --> E{生命周期钩子}
E -->|Vue 2: beforeDestroy| F[执行清理代码]
E -->|Vue 3: beforeUnmount| F
E -->|使用错误钩子| G[清理代码未执行]
G --> H[监听器未移除]
H --> I[功能失效]
H --> J[内存泄漏]
F --> K[监听器正确移除]
K --> L[功能正常]
```
## 修复优先级
### P0 - 立即修复(影响核心功能)
- ResizeHandler.js
- TopNav/index.vue
- Screenfull/index.vue
- RightPanel/index.vue
### P1 - 高优先级(影响用户体验)
- Editor/index.vue
- CountTo/index.vue
### P2 - 中优先级(影响特定页面)
- 所有图表组件和 mixins
## 预期效果
修复后:
- ✅ 侧边栏折叠/展开正常工作
- ✅ 顶部菜单响应式正常
- ✅ 全屏功能正常
- ✅ 右侧面板开关正常
- ✅ 无内存泄漏
- ✅ 无控制台警告
## 后续建议
1. **全局搜索其他 Vue 2 语法**:
```bash
grep -r "beforeDestroy\|destroyed\|\$listeners\|\$on\|\$off" --include="*.vue" --include="*.js"
```
2. **考虑完全迁移到 Vue 3**:
- 移除 `@vue/compat` 依赖
- 使用纯 Vue 3 API
- 更新所有组件库到最新版本
3. **添加 ESLint 规则**:
检测和阻止使用已弃用的 Vue 2 API

View File

@@ -0,0 +1,198 @@
---
name: 采购模块三页面开发计划
overview: 基于 PRD 文档和已有代码,完成采购计划单、采购订单、采购计划需求表三个页面的前后端开发与联调,按业务流程依赖关系分阶段推进。
todos:
- id: phase1-backend
content: 阶段一后端:补全 MpPurchase 实体字段、Mapper 双视图查询、引入/审核/genCode 接口
status: completed
- id: phase1-frontend-list
content: 阶段一前端列表:采购计划单 index.vue 明细/单据双视图 + 快捷标签 + 底部汇总
status: completed
- id: phase1-frontend-form
content: 阶段一前端表单:采购计划单 form.vue 表头19字段 + 子表12列 + 引入弹窗(层级展开) + 按钮组
status: completed
- id: phase1-test
content: 阶段一联调:新增→引入→保存→审核完整流程自测
status: completed
- id: phase2-backend
content: 阶段二后端:确认 PoOrder 实体、引入采购计划明细接口、金额计算、到货回写
status: completed
- id: phase2-frontend-list
content: 阶段二前端列表:采购订单 index.vue 明细/单据双视图 + 底部订单/到货数量汇总
status: completed
- id: phase2-frontend-form
content: 阶段二前端表单:采购订单 form.vue 表头17字段 + 子表14列 + 供应商弹窗 + 引入弹窗 + 金额自动计算
status: completed
- id: phase2-test
content: 阶段二联调:新增→选供应商→引入→单价金额→保存→审核完整流程自测
status: completed
- id: phase3-backend
content: 阶段三后端:实现 /mp/plan/need/list 查询接口(物料汇总+库存可用量) + 导出接口
status: completed
- id: phase3-frontend
content: 阶段三前端:新建 need.vue 单文件组件(搜索+4按钮+快捷标签+12列表格+3项底部汇总+负值高亮)
status: completed
- id: phase3-test
content: 阶段三联调:报表查询+筛选+导出自测
status: completed
isProject: false
---
# 采购模块三页面开发计划
## 业务流程全景
```mermaid
flowchart LR
MBOM["物料清单MBOM<br>供应方式=采购"] --> PurchasePlan["采购计划单<br>/mp/plan/purchase"]
PurchasePlan -->|"引入计划明细"| PurchaseOrder["采购订单<br>/po/purchase/order"]
PurchasePlan -->|"数据汇总"| NeedReport["采购计划需求表<br>/mp/plan/need"]
PurchaseOrder -->|"到货引入"| Checkin["采购到货单"]
Supplier["供应商档案"] -->|"选择供应商"| PurchaseOrder
```
三个页面存在上下游依赖关系:**采购计划单 → 采购订单 → 采购计划需求表**,开发顺序应按此依赖链推进。
---
## 现有代码基础
已有可用的前后端骨架代码(来自 `erp-frontend-vue``mom-backend`
- **采购计划单**: 前端 `erp-frontend-vue/src/views/Production/PurchasePlan/` (index.vue + form.vue),后端 `MpPurchaseController.java` + `MpPurchaseMapper.xml`API `purchasePlan.ts`
- **采购订单**: 前端 `erp-frontend-vue/src/views/Purchasing/Order/` (index.vue + form.vue),后端 `PoOrderController.java` + `PoOrderMapper.xml`API `purchaseOrder.ts`
- **采购计划需求表**: 前端无独立组件Production/Reports 下有 DetailReport/TotalReport 可参考),后端接口 `GET /mp/plan/need/list` 已在前端开发规范中定义
开发重点是**对齐 PRD 文档中的字段、交互和业务逻辑**,而非从零开始。
---
## 阶段一采购计划单P0 - 核心上游)
> PRD: [mom系统采购计划单-页面开发说明文档.md](prd/mom系统采购计划单-页面开发说明文档.md)
> 现有代码: `erp-frontend-vue/src/views/Production/PurchasePlan/` + `mom-backend/.../mp/`
### 后端任务
- **补全 MpPurchase 实体字段**: 对照 PRD 5.1 节 erp_mp_purchase 表,确认 `MpPurchase.java` 包含 businessType, businessStatus, deptId, deptName, operatorId, operatorName, approverId, approverName, approveDate, needType 等字段(部分已在 `alter_erp_mp_purchase_add_columns.sql` 中添加)
- **补全 Mapper XML 查询**: `MpPurchaseMapper.xml` 需支持明细视图(物料维度 70 行)和单据视图(按 purchaseCode 聚合 31 行)两种查询模式;补充底部汇总 SQLSUM purchaseQty, orderedQty
- **引入接口**: 确认 `/erp/mp/purchase/lead` 接口返回生产计划单列表(含展开的物料明细:需求数量/可用量/已采数量/未采数量),对齐 PRD 4.4 节引入弹窗的 8 列 + 展开 7 列
- **审核/反审核**: 确认审核时填充 approverId/approverName/approveDate反审核时校验无下游采购订单引用
- **编码生成**: 确认 genCode 接口生成 CGJH + 6 位流水号
### 前端任务
- **列表页 index.vue — 双视图切换**: 对照 PRD 3.1/3.2 节实现明细视图11 列:序号/跟单编号/订单交期/单据编码/单据状态/物料名称/物料编码/采购数量/已订数量/单据日期/采购说明和单据视图9 列 + 操作列 查看/编辑/删除);工具栏按钮明细=[搜索/单据/查询所有/新增/导出],单据=[搜索/明细/查询所有/新增/删除/审核/反审核]
- **列表页 — 快捷筛选标签**: 物料分类标签(成品/原材料/五金件等),来源动态加载
- **列表页 — 底部汇总**: 采购数量 + 已订数量合计
- **表单页 form.vue — 表头**: 对照 PRD 4.2 节 19 个字段5 列布局),区分新增/编辑/查看模式的可编辑状态
- **表单页 — 物料信息子表**: 12 列(序号/物料编码/物料名称/型号规格/主计量/需求日期/需求数量/可用量/采购数量/已订数量/采购说明/操作)
- **表单页 — 引入弹窗**: 标题="选择生产计划单",搜索=[销售单号/物料编码/物料名称/日期范围],父行 8 列(销售员/销售单号/订单交期/计划单号/物料编码/物料名称/主计量/数量),展开子行 7 列(物料编码/物料名称/需求数量/可用量/已采数量/未采数量/备注)
- **表单页 — 按钮组**: 新增=[保存/取消/审核/反审核/收起/引入],查看=[新增/编辑/审核/反审核/打印/操作/收起 + 上一条/下一条],编辑=[保存/撤回/审核/反审核/操作/收起/引入/新增物料]
### 验收标准
- 明细视图 / 单据视图切换正常,数据行数一致
- 新增 → 引入 → 保存 → 审核 完整流程跑通
- 底部汇总数据正确
---
## 阶段二采购订单P0 - 核心执行单据)
> PRD: [mom系统采购订单-页面开发说明文档.md](prd/mom系统采购订单-页面开发说明文档.md)
> 现有代码: `erp-frontend-vue/src/views/Purchasing/Order/` + `mom-backend/.../po/`
### 后端任务
- **确认 PoOrder / PoOrderLine 实体**: 对照 PRD 5.1/5.2 节 erp_po_order22 字段)和 erp_po_order_line18 字段),确认 `PoOrder.java``PoOrderLine.java` 字段完整
- **引入接口(采购计划单明细)**: 确认 `/erp/po/order/lead``/leadInto` 接口返回采购计划单明细10 列:计划单号/销售员/跟单编号/订单交期/物料编码/物料名称/需求日期/需求数量/已采数量/未采数量),支持按跟单编号/料品大类/物料编码/物料名称搜索
- **供应商选择**: 确认 `/erp/po/supplier/list` 返回 7 列(序号/供应商名称/电话/业务联系人/手机号/状态/操作),注意 ERP 用 supplier_id/supplier_name vs MOM 用 vendor_id/vendor_name 的字段名差异
- **金额计算**: 确认 line.amount = line.quantity * line.unitPrice表头 totalQuantity / totalAmount 为明细行合计
- **到货数量回写**: 确认到货单审核后回写 order_line.arrived_quantity
- **Mapper XML**: `PoOrderMapper.xml` 需支持明细视图83 行物料维度含供应商列和单据视图44 行单据维度);底部汇总 SUM(quantity) 作为订单数量
### 前端任务
- **列表页 index.vue — 双视图**: 明细视图 12 列(序号/跟单编号/计划编号/单据编码/单据状态/供应商/物料名称/物料编码/需求日期/采购数量/到货数量/单据日期),单据视图 9 列 + 操作列
- **表单页 form.vue — 表头**: 对照 PRD 4.2 节 17 字段(含供方选择弹窗、到货日期、采购合同上传、合同号),区分新增/编辑/查看模式
- **表单页 — 物料子表**: 14 列(序号/跟单编号/计划单号/物料编码/物料名称/型号规格/主计量/需求日期/数量/单价/金额/到货数量/采购说明/操作),底部合计行
- **供应商选择弹窗**: 标题="选择供应商",搜索=[供应商名称/业务联系人],按钮含"快速添加"7 列表格 79 行数据
- **引入弹窗(采购计划单明细)**: 标题="采购计划单明细"10 列,按钮=[搜索/采购退货单/全选/确定/取消]
- **按钮组差异**: 新增=[保存/取消/审核/反审核/收起/引入/新增物料],查看=[新增/编辑/审核/反审核/打印/操作/收起],编辑=[保存/撤回/审核/反审核/操作/收起/引入/新增物料],注意编辑页有"撤回"按钮而非"取消"
- **金额自动计算**: 数量 x 单价 = 金额,合计行实时更新
### 验收标准
- 新增 → 选择供应商 → 引入计划明细 → 修改单价 → 金额自动计算 → 保存 → 审核 完整流程
- 供应商弹窗正确加载(注意 supplier vs vendor 字段映射)
- 引入弹窗含全选和退货单切换按钮
---
## 阶段三采购计划需求表P1 - 只读报表)
> PRD: [mom系统采购计划需求表-页面开发说明文档.md](prd/mom系统采购计划需求表-页面开发说明文档.md)
> 现有代码: 前端无独立组件(需新建 `need.vue`),后端接口 `GET /mp/plan/need/list` 待实现
### 后端任务
- **实现查询接口**: `GET /erp/mp/plan/need/list`,基于 erp_mp_purchase 按物料维度查询,关联库存计算可用量,返回 12 列(销售订单号/计划单号/物料编码/物料名称/需求数量/可用量/采购数量/已订数量/未订数量/单据日期/采购说明)
- **实现导出接口**: `GET /erp/mp/plan/need/export`,参数同查询接口
- **未订数量计算**: unorderedQty = purchaseQty - orderedQty
- **可用量**: 查询库存可用量(可为负值,表示缺料)
### 前端任务
- **新建 need.vue**: 单文件组件,仅列表页无详情页
- **搜索区**: 6 个搜索项(销售订单号/物料编码/物料名称/开始日期/结束日期/下拉选择)
- **工具栏**: 4 按钮(搜索/查询所有/导出/打印)+ 快捷标签(原材料/零部件/五金)
- **表格**: 12 列,底部汇总 3 项(采购数量/已订数量/未订数量)
- **可用量负值高亮**: 可用量 < 0 时红色显示
- **路由注册**: `/production/purchase-need` 或复用 `/mp/plan/need`
### 验收标准
- 页面加载显示采购需求汇总数据
- 快捷标签筛选正常
- 导出 Excel 正常
- 底部 3 项汇总数据正确
---
## 开发依赖与顺序
```mermaid
gantt
title 采购模块开发甘特图
dateFormat YYYY-MM-DD
section 阶段一_采购计划单
后端补全字段与接口 :a1, 2026-02-08, 2d
前端列表页双视图 :a2, after a1, 2d
前端表单页含引入弹窗 :a3, after a2, 3d
联调与自测 :a4, after a3, 1d
section 阶段二_采购订单
后端引入与金额逻辑 :b1, after a1, 2d
前端列表页双视图 :b2, after b1, 2d
前端表单页含供应商弹窗 :b3, after b2, 3d
联调与自测 :b4, after b3, 1d
section 阶段三_需求报表
后端查询汇总接口 :c1, after a4, 1d
前端need_vue组件 :c2, after c1, 1d
联调与自测 :c3, after c2, 1d
```
---
## 关键技术注意事项
- **供应商字段映射**: ERP 用 `supplier_id/supplier_name/supplier_code`MOM 用 `vendor_id/vendor_name/vendor_code`表名也不同erp_po_supplier vs md_vendor接口调用和数据同步时需做字段转换
- **双视图模式**: 三个页面中采购计划单和采购订单都有明细/单据双视图,通过 `viewMode` 状态变量切换,共享搜索条件的公共字段
- **引入弹窗嵌套表格**: 采购计划单的引入弹窗需支持父行展开子行(可用量/未采数量等),采购订单的引入弹窗为平铺 10 列
- **金额计算**: 仅采购订单有单价/金额字段,采购计划单和需求表不涉及价格
- **状态流转**: 采购计划单和采购订单共用 DRAFT→APPROVED 流转,反审核需校验下游引用

View File

@@ -0,0 +1,64 @@
---
name: 采购订单PRD版本与手工新增物料补全
overview: 将采购订单开发说明文档版本升级至 2.3.0,在全文补全与「手动/手工新增物料」相关的引用、术语和业务规则,并统一截图数量说明。
todos: []
isProject: false
---
# 采购订单 PRD 版本更新与手工新增物料补全
## 现状
- 文档当前为 **2.2.0**2026-02-13已包含 **[4.3.1 手工新增物料](prd/mom系统采购订单-页面开发说明文档.md)** 的完整说明(操作流程、选择物料弹窗、与引入的区分)及两张截图引用。
- 用户需求:**版本更新**、**补全新功能****特别是手动新增物料**。即在不改动 4.3.1 主体内容的前提下,做版本号与日期的升级,并在全文档中补全对手工/手动新增物料的引用与规则,使“手动新增物料”在文档中更易发现、前后一致。
## 修改范围(仅文档,无代码)
### 1. 版本与元信息
- **[prd/mom系统采购订单-页面开发说明文档.md](prd/mom系统采购订单-页面开发说明文档.md)** 头部:
- 版本:`2.2.0``**2.3.0**`
- 更新日期:保持或设为本次修订日期(如 `2026-02-13`
- **采集脚本** 行:将「共 17 张截图」改为「共 19 张截图」2.2.0 已补充 2 张:可新增物料、点击添加物料)
### 2. 术语与可发现性(手动新增物料)
- **4.3.1 小节**:在首段前或标题后增加一句说明:**「本功能也称“手动新增物料”,与“手工新增物料”同义。」** 便于按“手动”检索。
- **目录**在「4. [新增/编辑页设计](#4-新增编辑页设计)」下增加一条四级目录:**「4.3.1 [手工(手动)新增物料](#431-手工新增物料)」**,便于从目录直接跳转到该功能。
### 3. 业务流程与按钮说明中的补全
- **0.3 采购订单内部业务流程表**:阶段 4「新增物料」一行「结果」列由「子表末尾新增空行」扩展为**「子表末尾新增空行;可通过「选择物料」选料并填数量/单价,见 4.3.1」**。
- **6.3 新增/编辑页按钮**:「新增物料」行,「结果」列由「行数+1」扩展为**「子表新增空行(行数+1选料与完整流程见 4.3.1」**。
### 4. 业务规则补全
- **第 10 章 业务规则**:在 **10.2 引入规则** 之后新增 **10.2.1 手工(手动)新增物料规则**(或作为 10.2 的补充段落):
- 说明与「引入」的区分:手工新增行无计划单/跟单来源,跟单编号/计划单号显示「手工单据」或「添加物料」;
- 必选物料:须通过「选择物料」弹窗选择物料,回填编码/名称/规格/计量单位;
- 数量、单价、需求日期、采购说明由用户填写,行金额 = 数量×单价 自动计算;
- 引用:「操作流程与选择物料弹窗详见 [4.3.1 手工新增物料](#431-手工新增物料)」。
### 5. 修订历史
-**修订历史** 表末尾新增一行 **2.3.0**
- **版本**2.3.0
- **日期**2026-02-13或实际修订日
- **修订内容**:版本更新至 2.3.0;补全新功能说明,重点补全**手动/手工新增物料**在业务流程(0.3)、按钮说明(6.3)、业务规则(10.2.1)中的引用与规则;目录增加 4.3.1 手工手动新增物料4.3.1 增加“手动新增物料”同义说明;截图总数更新为 19 张。
- **修订人**System或保留现有风格
## 不改动部分
- 4.3.1 的现有正文(操作流程表、选择物料弹窗、与引入的区分表)保持不变。
- 1.2 业务场景、1.4 截图表、4.3 子表列定义等已有对手工新增物料或截图的描述保持不变,仅在有需要时做最小化措辞微调(如与 10.2.1 一致)。
## 实施顺序建议
1. 头部版本、更新日期、截图数量
2. 目录增加 4.3.1 条目
3. 4.3.1 增加“手动新增物料”同义说明
4. 0.3 表、6.3 表补全
5. 第 10 章新增 10.2.1(或 10.2 补充段)
6. 修订历史新增 2.3.0
按上述顺序修改后,文档版本为 2.3.0,且“手动新增物料”在概述、流程、按钮、业务规则和目录中均有明确补全与交叉引用。

View File

@@ -0,0 +1,212 @@
---
name: 验证采购入库按钮修复
overview: 问题已解决!提供验证步骤和进一步诊断方法,确保采购入库页面的"新增"按钮正常工作。
todos: []
isProject: false
---
# 采购入库按钮修复 - 验证和测试计划
## 当前状态
问题**已经解决**!以下改进已经应用到代码中:
### 已完成的修复
#### 1. 移除了 `.prevent` 修饰符
**文件**: `[mom-backend-ui/src/views/mes/wm/itemrecpt/index.vue:57](mom-backend-ui/src/views/mes/wm/itemrecpt/index.vue)`
```vue
<!-- 修复前 -->
@click.prevent="handleAdd"
<!-- 修复后 -->
@click="handleAdd"
```
#### 2. 添加了完善的调试日志
`handleAdd` 方法中添加了详细的日志输出:
```javascript
handleAdd() {
console.log('[采购入库] handleAdd 方法被调用');
console.log('[采购入库] 当前状态:', { open, title, optType });
// ... 业务逻辑
console.log('[采购入库] Dialog 状态已更新:', { open, title, optType });
// DOM 检查
this.$nextTick(() => {
console.log('[采购入库] Dialog DOM 检查:', {
dialogExists, overlayExists
});
});
}
```
#### 3. 增强了 Dialog 监控
添加了 Dialog 生命周期事件:
- `@open` - Dialog 开始打开
- `@opened` - Dialog 完全打开
- `@close` - Dialog 关闭
#### 4. 创建了诊断工具
- `[mom-backend-ui/DEBUGGING-ITEMRECPT.md](mom-backend-ui/DEBUGGING-ITEMRECPT.md)` - 完整诊断指南
- `[mom-backend-ui/public/debug-itemrecpt.js](mom-backend-ui/public/debug-itemrecpt.js)` - 自动诊断脚本
- `[CHANGES-ITEMRECPT-BUTTON-FIX.md](CHANGES-ITEMRECPT-BUTTON-FIX.md)` - 变更记录
## 验证步骤
### 步骤 1: 基本功能测试
```mermaid
flowchart TD
A[打开采购入库页面] --> B[打开浏览器控制台F12]
B --> C[点击新增按钮]
C --> D{是否有日志输出?}
D -->|有| E[检查日志内容]
D -->|无| F[问题1:按钮未响应]
E --> G{Dialog是否打开?}
G -->|是| H[修复成功✓]
G -->|否| I[问题2:Dialog未显示]
F --> F1[运行诊断脚本]
I --> I1[查看DOM检查日志]
```
### 步骤 2: 控制台验证
1. 打开采购入库页面
2. 按 F12 打开开发者工具
3. 进入 Console 标签
4. 在 Filter 输入框输入: `[采购入库]`
5. 点击"新增"按钮
**预期输出**:
```
[采购入库] handleAdd 方法被调用
[采购入库] 当前状态: {open: false, title: "", optType: undefined}
[采购入库] Dialog 状态已更新: {open: true, title: "添加物料入库单", optType: "add"}
[采购入库] Dialog DOM 检查: {open: true, dialogExists: true, overlayExists: true}
[采购入库] Dialog 开始打开动画
[采购入库] Dialog 已完全打开
```
### 步骤 3: 运行自动诊断脚本
在浏览器控制台执行:
```javascript
fetch('/debug-itemrecpt.js').then(r => r.text()).then(eval)
```
该脚本会自动检查:
- 按钮是否存在于 DOM
- Vue 应用是否正常
- 用户权限是否正确
- Element Plus 是否加载
- Plus 图标是否正常
## 问题排查矩阵
| 现象 | 可能原因 | 解决方案 | 参考文档 |
| ------------------- | ----------- | --------------------------------- | --------------------------- |
| 按钮不存在于 DOM | 权限问题 | 检查用户是否有 `mes:wm:itemrecpt:add` 权限 | DEBUGGING-ITEMRECPT.md §问题1 |
| 无任何日志输出 | 事件未绑定或按钮被禁用 | 检查按钮 disabled 属性和 z-index | DEBUGGING-ITEMRECPT.md §问题2 |
| 有日志但 Dialog 未显示 | Dialog 渲染问题 | 检查 DOM 和 CSS查看 DOM 检查日志 | DEBUGGING-ITEMRECPT.md §问题3 |
| dialogExists: false | Vue 响应式问题 | 检查 open 变量,使用 Vue DevTools | DEBUGGING-ITEMRECPT.md §问题3 |
| 有错误日志 | 代码异常 | 查看 errorCaptured 日志详情 | 控制台错误栈 |
## 检查用户权限
在浏览器控制台执行:
```javascript
// 检查当前用户权限
window.$store?.getters?.permissions
// 或者检查是否包含特定权限
window.$store?.getters?.permissions?.includes('mes:wm:itemrecpt:add')
```
如果返回 `false` 或权限列表中不包含该权限,需要:
1. 联系管理员添加权限
2. 或者在角色管理中配置权限
## 使用 Vue DevTools 调试
1. 安装 Vue DevTools 浏览器扩展
2. 打开 Vue DevTools
3. 在组件树中找到 `Itemrecpt` 组件
4. 观察 `data` 中的变量:
- `open` - Dialog 显示状态
- `title` - Dialog 标题
- `form` - 表单数据
5. 点击按钮后实时查看变量变化
## 进一步诊断
如果按照上述步骤问题仍未解决,收集以下信息:
1. **浏览器信息**
- 浏览器类型和版本
- 操作系统版本
2. **控制台输出**
- 完整的日志输出(包含 [采购入库] 前缀的)
- 任何错误信息和堆栈
3. **权限信息**
```javascript
console.log('权限列表:', window.$store?.getters?.permissions)
```
4. **DOM 状态**
```javascript
console.log('按钮元素:', document.querySelector('button:contains("新增")'))
console.log('Dialog:', document.querySelector('.el-dialog'))
```
5. **Vue DevTools 截图**
- Itemrecpt 组件的 data 状态
- open 变量的值
## 相关文档
- 详细诊断指南: `[DEBUGGING-ITEMRECPT.md](mom-backend-ui/DEBUGGING-ITEMRECPT.md)`
- 完整变更记录: `[CHANGES-ITEMRECPT-BUTTON-FIX.md](CHANGES-ITEMRECPT-BUTTON-FIX.md)`
- 诊断脚本: `[debug-itemrecpt.js](mom-backend-ui/public/debug-itemrecpt.js)`
## 后续行动
如果验证通过:
- 无需进一步操作,问题已解决
如果验证失败:
1. 按照问题排查矩阵定位具体问题
2. 查阅 DEBUGGING-ITEMRECPT.md 获取详细解决方案
3. 收集诊断信息寻求技术支持
## 总结
修复内容:
- 移除不必要的 `.prevent` 修饰符
- 添加 18 个标准化调试日志
- 增强 Dialog 事件监控
- 创建完整的诊断工具集
验证要点:
- 点击按钮后应看到 `[采购入库]` 开头的日志
- Dialog 应正常打开
- 所有操作应有清晰的日志记录