From 9c1f52078dd0efdee5f1fdb37e207364ee49c32f Mon Sep 17 00:00:00 2001 From: Developer Date: Mon, 6 Jul 2026 11:21:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=A3=85=E9=85=8D=E3=80=81?= =?UTF-8?q?=E7=B2=BE=E5=B7=A5=E8=BD=A6=E9=97=B4=E3=80=81=E6=8A=80=E6=9C=AF?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E3=80=81=E4=BB=93=E5=82=A8=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=B7=A5=E5=BA=8F=E5=B7=A5=E4=BB=B7?= =?UTF-8?q?=E3=80=81=E7=94=9F=E4=BA=A7=E5=AE=A1=E6=A0=B8=E3=80=81=E4=B8=89?= =?UTF-8?q?=E6=A5=BC=E4=BB=93=E5=BA=93=E5=8F=AF=E8=A7=86=E5=8C=96=E7=AD=89?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=8A=E6=96=87=E6=A1=A3SQL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 7 + docs/JY1.0-阶段功能需求文档.md | 371 ++++-- .../三楼仓库可视化界面设计方案.md | 919 +++++++++++++++ docs/产品报缺/产品报缺补货需求.docx | Bin 0 -> 197757 bytes .../MES提交审批到质检入库全链路测试报告.md | 235 ++++ .../工序工价与生产任务审核开发说明.md | 423 +++++++ .../工序工价开发说明.md | 248 ++++ .../生产任务审核开发说明.md | 214 ++++ docs/物料库位设置/物料库位功能调整测试报告.md | 398 +++++++ docs/物料库位设置/物料库位功能调整设计方案.md | 227 +++- .../核心物料搜索栏添加物料编码查询测试报告.md | 158 +++ .../核心物料搜索栏添加物料编码查询设计方案.md | 0 .../物料编号搜索功能设计说明.md | 0 docs/零件改制/03-推进台账.md | 14 +- docs/零件改制/04-任务矩阵.md | 5 +- docs/零件改制/05-验收证据.md | 167 +++ docs/零件改制/06-决策记录.md | 70 ++ docs/零件改制/零件改制入库链路测试报告.md | 299 +++++ package.json | 2 + sql/三楼仓库可视化_存储过程.sql | 94 ++ sql/仓储管理_入库记录_入库单去重.sql | 238 ++++ sql/工序工价_存储过程.sql | 1037 +++++++++++++++++ sql/工时统计_添加工价总价.sql | 236 ++++ sql/机加工MES_加工完成整修审核_查询审核.sql | 381 ++++++ ...心物料搜索栏_物料编码查询_存储过程调整.sql | 259 ++++ sql/生产审核菜单组件路径修正.sql | 11 + sql/采购入库合同明细_关联未入库最新到货.sql | 50 + sql/零件改制_发起改制_精确基本件.sql | 315 +++++ .../ReceiveAssemblyTask/index.vue | 2 +- .../SeikoWorkshop/ProcessPrice/index.vue | 774 ++++++++++++ .../ProductionCompletionAudit/index.vue | 457 ++++++++ .../WorkingHoursStatistics/index.vue | 52 +- .../MaterialMaintain/index.vue | 7 +- .../PartModificationOrder/index.vue | 56 +- .../InventoryCheck/index.vue | 2 +- .../InventoryQuery/index.vue | 10 +- .../InventoryRecord/index.vue | 29 +- .../MaterialLocation/index.vue | 4 +- .../MaterialRecord/index.vue | 40 +- .../ReturnRecord/index.vue | 16 +- .../ThirdFloorWarehouse/index.vue | 962 +++++++++++++++ .../WarehousingRecord/WarehousingRecord.vue | 6 +- static/config.js | 4 +- 43 files changed, 8566 insertions(+), 233 deletions(-) create mode 100644 docs/三楼仓库可视化/三楼仓库可视化界面设计方案.md create mode 100644 docs/产品报缺/产品报缺补货需求.docx create mode 100644 docs/工序工价与生产任务审核/MES提交审批到质检入库全链路测试报告.md create mode 100644 docs/工序工价与生产任务审核/工序工价与生产任务审核开发说明.md create mode 100644 docs/工序工价与生产任务审核/工序工价开发说明.md create mode 100644 docs/工序工价与生产任务审核/生产任务审核开发说明.md create mode 100644 docs/物料库位设置/物料库位功能调整测试报告.md create mode 100644 docs/物料编码搜索功能/核心物料搜索栏添加物料编码查询测试报告.md rename docs/{ => 物料编码搜索功能}/核心物料搜索栏添加物料编码查询设计方案.md (100%) rename docs/{ => 物料编码搜索功能}/物料编号搜索功能设计说明.md (100%) create mode 100644 docs/零件改制/零件改制入库链路测试报告.md create mode 100644 sql/三楼仓库可视化_存储过程.sql create mode 100644 sql/仓储管理_入库记录_入库单去重.sql create mode 100644 sql/工序工价_存储过程.sql create mode 100644 sql/工时统计_添加工价总价.sql create mode 100644 sql/机加工MES_加工完成整修审核_查询审核.sql create mode 100644 sql/核心物料搜索栏_物料编码查询_存储过程调整.sql create mode 100644 sql/生产审核菜单组件路径修正.sql create mode 100644 sql/采购入库合同明细_关联未入库最新到货.sql create mode 100644 sql/零件改制_发起改制_精确基本件.sql create mode 100644 src/views/SeikoWorkshop/ProcessPrice/index.vue create mode 100644 src/views/SeikoWorkshop/ProductionCompletionAudit/index.vue create mode 100644 src/views/WarehouseManagement/ThirdFloorWarehouse/index.vue diff --git a/AGENTS.md b/AGENTS.md index 301be55d..486325b8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -44,6 +44,10 @@ API 文件按业务模块组织在 `src/api/` 目录下,子目录与业务模 环境配置集中在 `static/config.js` 中,通过导出常量供 `src/utils/request.js` 引用。包含主服务地址、立库接口地址、文件上传下载路径、WebSocket 地址等。环境切换通过注释切换 IP 地址实现,不使用 `.env` 文件。修改配置时需同时关注 `request.js` 中的引用。 +## 后端数据库 + +后端使用 SQL Server 数据库,连接信息如下:IP 地址 `192.168.1.27`,数据库名 `ERPTOOL_JY_20250826Back`,账号 `sa`,密码 `126.com`。 + ## 文件上传下载 文件上传使用多个专用处理器:`uploadFile.ashx`(通用上传)、`MESUploadFile.ashx`(MES 系统上传)、`uploadOP.ashx`(工序上传)、`uploadPerson.ashx`(人员上传)等。文件下载使用 `downloadFile.ashx` 和 `MESDownloadFile.ashx`。Excel 导出使用 `ExcelDownLoad` 配置指向 `MESCommonBase.ashx`,前端通过 `this.exportExcel_NPOI(param)` 触发下载。图片查看使用 `v-viewer` 插件。 @@ -75,3 +79,6 @@ SVG 图标位于 `src/icons/svg/` 目录,通过 `svg-sprite-loader` 自动注 ## GPT/Codex 执行日志 每次 GPT/Codex 执行完成后,将完整的执行过程使用日志追加到 `/gptlog-process/gpdlog.md`,日志使用中文。 + +日志包含提问和结论以及完整的执行过程,写入该文件的日志内容必须使用中文记录。 + diff --git a/docs/JY1.0-阶段功能需求文档.md b/docs/JY1.0-阶段功能需求文档.md index ff9c66c0..5125dd32 100644 --- a/docs/JY1.0-阶段功能需求文档.md +++ b/docs/JY1.0-阶段功能需求文档.md @@ -15,20 +15,21 @@ 5. 优化现有看板数据展示,并新增仓库、采购等业务看板。 6. 增加新订单语音播报能力,提升部门电视机、现场广播等场景下的消息触达效率。 7. 完善质检 PDA 应急方案,在 PDA 设备故障时使用手机扫码保障生产不中断。 +8. 三楼仓库可视化界面,直观展示各库位状态及整体仓储情况 -## 03-需求一:默认库位设置功能调整 +## 需求一:优化仓储相关业务流程,减少物料维护页面职责过重的问题 -### 3.1 需求背景 +### 1 需求背景 -当前“设置默认库位”功能位于物料标准维护或物料标准相关页面中,导致物料基础维护页面承载了仓储业务配置职责。为降低页面复杂度,并使库位规则更贴近入库业务,需要将默认库位设置从物料标准维护中移出。 +由仓库主管提出.当前“设置默认库位”功能位于物料标准维护或物料标准相关页面中,导致物料基础维护页面承载了仓储业务配置职责。为降低页面复杂度,并使库位规则更贴近入库业务,需要将默认库位设置从物料标准维护中移出,该功能转到由仓库人员决定库位。 -### 3.2 功能目标 +### 2 功能目标 1. 去除物料标准维护中的“设置默认库位”入口和相关操作。 2. 将默认库位设置功能迁移到其他更合适的仓储组件,或新建“默认库位设置”组件。 3. 物料入库选择库位时,根据该物料是否存在默认库存或库位库存显示不同的库位范围。 -### 3.3 业务规则 +### 3 业务规则 1. 如果物料没有默认库存或没有可识别的默认库位库存,入库时显示全库位选择。 2. 如果物料已有库存库位,入库时优先显示该物料已有库存的库位选择。 @@ -36,7 +37,7 @@ 4. 新组件需要支持按物料编码、物料名称、图号、规格型号等条件查询物料。 5. 默认库位设置后,应能被物料入库、库存盘点、库存查询等仓储业务读取。 -### 3.4 前端范围 +### 4 前端范围 1. 移除物料标准维护页面中的默认库位设置按钮、弹窗和相关方法。 2. 新增或迁移默认库位设置组件,建议放入仓储管理模块。 @@ -45,13 +46,31 @@ - 有库存时显示该物料已有库存库位。 4. 保持 Vue 2 Options API 和 Element UI 原有开发风格。 -### 3.5 后端范围 +### 5 后端范围 1. 梳理现有默认库位相关存储过程、表字段和调用页面。 2. 根据新组件补充查询、保存、删除默认库位的接口。 3. 入库库位查询过程需支持按物料返回全库位或已有库存库位。 -### 3.6 验收标准 +### 6 功能实现流程图 + +```mermaid +flowchart TD + A["开始:调整默认库位设置功能"] --> B["前端移除物料标准维护中的默认库位入口"] + B --> C["新建或迁移默认库位设置组件"] + C --> D["组件提供物料查询和默认库位维护"] + D --> E["调用后端默认库位查询/保存/删除过程"] + E --> F["数据库保存物料与默认库位关系"] + F --> G["物料入库页面选择物料"] + G --> H{"该物料是否已有库存库位"} + H -- "是" --> I["查询并显示该物料已有库存库位"] + H -- "否" --> J["查询并显示全库位或默认库位候选"] + I --> K["用户选择库位并提交入库"] + J --> K + K --> L["刷新入库、库存盘点、库存查询相关数据"] +``` + +### 7 验收标准 1. 物料标准维护页面不再出现默认库位设置入口。 2. 新默认库位设置组件可完成查询、设置、修改、删除。 @@ -59,19 +78,19 @@ 4. 物料已有库存库位时,入库页面只显示符合规则的库位。 5. 默认库位变更后,相关仓储页面读取结果一致。 -## 04-需求二:现有查询功能增加物料编码查询 +## 需求二:提升物料查询效率,在现有查询功能中统一补充物料编码查询能力 -### 4.1 需求背景 +### 1 需求背景 -系统中已有多个物料查询入口,但部分页面只能按物料名称、图号、规格型号等条件查询,无法直接按物料编码定位,影响仓储、销售、技术、装配等场景的查询效率。 +由罗伟提出.系统中已有多个物料查询入口,但部分页面只能按物料名称、图号、规格型号等条件查询,无法直接按物料编码定位,影响仓储、销售、技术、装配等场景的查询效率,以及查询准确性。 -### 4.2 功能目标 +### 2 功能目标 1. 在现有涉及物料查询的组件中新增“物料编码”查询条件。 2. 物料编码查询需要与原有条件组合查询。 3. 查询结果、导出结果、选择弹窗结果保持一致。 -### 4.3 覆盖范围 +### 3 覆盖范围 优先覆盖以下类型页面: @@ -83,7 +102,7 @@ | 销售管理 | 订单管理、订单审核、订单查询 | 物料选择弹窗 | | 装配管理 | 接收装配任务、接收滑台装配任务 | 物料选择弹窗 | -### 4.4 前端规则 +### 4 前端规则 1. 搜索栏新增 `物料编码` 输入框。 2. 输入框 placeholder 可使用“物料编码”或“物料编号”,但传参建议统一使用 `物料编码`。 @@ -91,7 +110,7 @@ 4. 导出功能应同步携带物料编码条件。 5. 不新增第三方库,不改变现有 `CreateData`、`ExecDatabase`、`getTable` 调用模式。 -### 4.5 后端规则 +### 5 后端规则 1. 相关查询存储过程增加可选参数: - `物料编码_check` @@ -100,26 +119,44 @@ 3. 传入物料编码时,应支持模糊查询或按现场确认规则查询。 4. 导出过程与页面查询过程保持条件一致。 -### 4.6 验收标准 +### 6 功能实现流程图 + +```mermaid +flowchart TD + A["开始:现有查询补充物料编码"] --> B["梳理涉及物料查询的页面和弹窗"] + B --> C["搜索栏或弹窗新增物料编码输入框"] + C --> D["查询方法拼接物料编码_check和物料编码参数"] + D --> E["调用原有CreateData/ExecDatabase/getTable流程"] + E --> F["后端查询过程接收物料编码可选参数"] + F --> G{"是否传入物料编码"} + G -- "是" --> H["按物料编码追加过滤条件"] + G -- "否" --> I["沿用原有查询条件"] + H --> J["返回查询结果"] + I --> J + J --> K["表格或物料选择弹窗刷新"] + K --> L["导出流程同步携带相同物料编码条件"] +``` + +### 7 验收标准 1. 用户可通过物料编码直接查询目标物料。 2. 物料编码可与物料名称、图号、规格型号等条件组合查询。 3. 查询和导出数据一致。 4. 所有改造页面无模板解析错误、无明显布局错位。 -## 05-需求三:车间派工组件移动端自适应 +## 需求三:改善移动端使用体验,支持车间派工在手机或移动终端上自适应展示和操作 -### 5.1 需求背景 +### 1 需求背景 -车间派工业务需要在移动设备上查看和操作,当前桌面端布局在手机或窄屏设备上可能存在表格过宽、按钮拥挤、筛选条件不易操作等问题。 +由车间主管提出.车间派工业务需要在移动设备上查看和操作,当前桌面端布局在手机或窄屏设备上可能存在表格过宽、按钮拥挤、筛选条件不易操作等问题。 -### 5.2 功能目标 +### 2 功能目标 1. 开发车间派工组件的移动端自适应布局。 2. 保持桌面端原有操作习惯不受影响。 3. 移动端重点保证查询、查看、派工、确认等高频操作可用。 -### 5.3 前端要求 +### 3 前端要求 1. 使用响应式样式适配手机、平板、窄屏电脑。 2. 搜索条件在移动端可折叠或纵向排列。 @@ -128,27 +165,44 @@ 5. 弹窗在移动端宽度应适配屏幕,不应超出视口。 6. 不引入 Vue 3、Composition API 或新的 UI 库。 -### 5.4 重点场景 +### 4 重点场景 1. 手机查看待派工任务。 2. 手机按订单、物料、工序、人员等条件筛选。 3. 手机进入派工明细并提交。 4. 手机查看派工状态、数量、人员、设备等关键字段。 -### 5.5 验收标准 +### 5 功能实现流程图 + +```mermaid +flowchart TD + A["开始:车间派工移动端适配"] --> B["梳理车间派工桌面端页面结构和核心操作"] + B --> C["识别搜索区、列表区、明细区、操作按钮"] + C --> D["增加响应式样式和移动端布局规则"] + D --> E{"当前屏幕宽度是否为移动端"} + E -- "是" --> F["搜索条件纵向排列或折叠展示"] + F --> G["表格转为横向滚动或核心字段卡片列表"] + G --> H["弹窗宽度和按钮点击区域适配手机"] + E -- "否" --> I["保留桌面端原有布局"] + H --> J["调用原有查询、派工、提交接口"] + I --> J + J --> K["按移动端和桌面端分别验证页面与业务操作"] +``` + +### 6 验收标准 1. 375px、414px、768px、1366px 宽度下页面可正常展示。 2. 移动端无关键按钮遮挡、重叠、不可点击问题。 3. 桌面端布局保持稳定。 4. 派工提交、查询、刷新等原有功能正常。 -## 06-需求四:库存盘点及物料系列、库位编辑优化 +## 需求四:完善库存盘点、物料系列、库位编辑、入库库位选择等库存基础能力 -### 6.1 需求背景 +### 1 需求背景 -库存盘点需要更细粒度筛选物料,并支持对盘点库位进行维护。当前盘点和入库库位选择逻辑需要与物料库存库位更紧密关联。 +由罗伟提出.库存盘点需要更细粒度筛选物料,并支持对盘点库位进行维护。当前盘点和入库库位选择逻辑需要与物料库存库位更紧密关联。 -### 6.2 功能目标 +### 2 功能目标 1. 新增“系列”字段,用于物料筛选和盘点筛选。 2. 在物料维护组件中支持编辑物料系列。 @@ -156,14 +210,14 @@ 4. 库存盘点组件添加编辑库位功能。 5. 物料入库组件的库位选择只显示有该物料的库位。 -### 6.3 物料维护要求 +### 3 物料维护要求 1. 物料维护列表展示“系列”字段。 2. 新增、编辑物料时可维护“系列”。 3. 系列字段建议使用中文字段名 `系列`。 4. 系列可根据现场数据情况使用输入框或下拉框。 -### 6.4 库存盘点要求 +### 4 库存盘点要求 1. 搜索栏增加“系列”筛选条件。 2. 支持按系列查询物料盘点数据。 @@ -171,13 +225,13 @@ 4. 表格展示需要包含系列字段,便于盘点人员核对。 5. 增加编辑库位功能,可调整物料对应盘点库位。 -### 6.5 物料入库要求 +### 5 物料入库要求 1. 入库时选择库位只显示有该物料的库位。 2. 如果该物料没有任何库存库位,需要结合需求一规则显示全库位或默认库位候选。 3. 库位下拉数据需要避免显示与该物料无关且容易误选的库位。 -### 6.6 后端要求 +### 6 后端要求 1. 物料基础表或相关视图增加 `系列` 字段。 2. 物料维护查询、新增、编辑过程支持系列字段。 @@ -185,7 +239,27 @@ 4. 库位编辑过程需要记录修改人、修改时间。 5. 入库库位查询过程按物料库存库位过滤。 -### 6.7 验收标准 +### 7 功能实现流程图 + +```mermaid +flowchart TD + A["开始:库存盘点和物料系列优化"] --> B["数据库物料基础数据增加系列字段"] + B --> C["物料维护组件新增系列展示和编辑"] + C --> D["保存物料系列到后端"] + D --> E["库存盘点组件搜索栏增加系列筛选"] + E --> F["调用盘点查询过程并传入系列参数"] + F --> G["盘点表格展示物料、库存、系列、库位等信息"] + G --> H["用户编辑盘点库位"] + H --> I["调用库位编辑过程并记录修改人和修改时间"] + I --> J["刷新库存盘点列表"] + J --> K["物料入库选择物料"] + K --> L["按物料查询已有库存库位"] + L --> M{"是否存在该物料库位"} + M -- "是" --> N["入库库位下拉只显示该物料库位"] + M -- "否" --> O["按默认库位规则显示候选库位"] +``` + +### 8 验收标准 1. 物料维护可新增和编辑系列字段。 2. 库存盘点可按系列筛选数据。 @@ -193,13 +267,13 @@ 4. 物料入库库位选择符合“只显示该物料相关库位”的规则。 5. 相关查询、保存后刷新数据一致。 -## 07-需求五:看板优化 +## 需求五:优化现有看板数据展示,并新增仓库、采购等业务看板 -### 7.1 需求背景 +### 1 需求背景 -现场看板需要更清晰地展示仓库、采购、订单、库存等业务状态。现有看板需要数据口径优化,同时新增部分业务看板。 +由罗总提出,开会讨论得出.现场看板需要更清晰地展示仓库、采购、订单、库存等业务状态。现有看板需要数据口径优化,同时新增部分业务看板。 -### 7.2 功能目标 +### 2 功能目标 1. 新增仓库看板组件。 2. 新增或优化采购看板组件。 @@ -207,7 +281,7 @@ 4. 仓库看板展示入库单滚动信息。 5. 采购看板展示仍在采购中的合同。 -### 7.3 仓库看板要求 +### 3 仓库看板要求 1. 展示入库单滚动列表。 2. 滚动内容建议包括入库单号、供应商、物料名称、物料编码、数量、入库日期、状态。 @@ -215,21 +289,40 @@ 4. 大屏展示时文字清晰,不出现字段重叠。 5. 支持异常状态突出显示,例如待处理、待上架、未完成。 -### 7.4 采购看板要求 +### 4 采购看板要求 1. 展示仍在采购中的合同。 2. 合同状态口径需要明确,例如未完成、采购中、部分到货、逾期未到。 3. 建议展示合同号、供应商、物料、数量、已到数量、未到数量、交期、状态。 4. 对逾期或临近交期的数据进行醒目提示。 -### 7.5 现有看板优化要求 +### 5 现有看板优化要求 1. 梳理现有看板数据来源和字段含义。 2. 对不准确、不及时或口径不一致的数据进行调整。 3. 保持大屏自适应显示效果。 4. 对滚动、刷新、排序、状态颜色做统一规范。 -### 7.6 验收标准 +### 6 功能实现流程图 + +```mermaid +flowchart TD + A["开始:看板新增与优化"] --> B["梳理现有看板组件和数据接口"] + B --> C["确认仓库看板、采购看板、现有看板数据口径"] + C --> D["新增仓库看板组件"] + C --> E["新增或优化采购看板组件"] + C --> F["调整现有看板数据查询逻辑"] + D --> G["查询入库单数据并生成滚动列表"] + E --> H["查询采购中的合同和交期状态"] + F --> I["统一字段、排序、状态颜色、刷新频率"] + G --> J["大屏页面自动滚动展示"] + H --> J + I --> J + J --> K["按刷新频率重新拉取数据"] + K --> L["验证大屏分辨率、滚动、刷新和数据准确性"] +``` + +### 7 验收标准 1. 仓库看板可滚动展示入库单数据。 2. 采购看板可展示采购中的合同。 @@ -237,27 +330,27 @@ 4. 大屏展示无明显错位、遮挡、空白异常。 5. 自动刷新不影响页面稳定性。 -## 08-需求六:语音播报 +## 需求六:增加新订单语音播报能力,提升部门电视机、现场广播等场景下的消息触达效率 -### 8.1 需求背景 +### 1 需求背景 -当系统产生新的订单或重要业务消息时,需要在部门电视机或全场广播中自动播报,类似商家外卖新订单语音提醒,减少人工盯屏和漏看消息。 +由罗总提出,开会讨论的出.当系统产生新的订单或重要业务消息时,需要在部门电视机或全场广播中自动播报,类似商家外卖新订单语音提醒,减少人工盯屏和漏看消息。 -### 8.2 功能目标 +### 2 功能目标 1. 新订单产生时触发语音播报。 2. 支持部门电视机播报或全场广播播报。 3. 播报内容简洁明确,便于现场人员快速理解。 4. 后续可扩展到采购到货、异常提醒、质检任务等事件。 -### 8.3 播报场景 +### 3 播报场景 1. 新订单生成。 2. 新订单分配到指定部门。 3. 订单状态发生关键变化。 4. 后续可扩展为库存预警、采购逾期、质检待处理等。 -### 8.4 播报内容建议 +### 4 播报内容建议 新订单播报示例: @@ -271,7 +364,7 @@ 技术中心有新的图纸确认任务,请及时处理。 ``` -### 8.5 技术要求 +### 5 技术要求 1. 前端可使用浏览器语音能力或播放预生成音频。 2. 如果用于电视机浏览器,需要确认浏览器是否允许自动播放声音。 @@ -279,14 +372,33 @@ 4. 新消息检测可采用轮询、WebSocket 或已有消息接口。 5. 需要增加播报开关、播报范围、播报频率、防重复播报规则。 -### 8.6 权限和配置 +### 6 权限和配置 1. 管理员可配置是否启用语音播报。 2. 可按部门配置播报内容和播报设备。 3. 同一订单不应重复无限播报。 4. 需要记录已播报状态或播报日志,便于追查。 -### 8.7 验收标准 +### 7 功能实现流程图 + +```mermaid +flowchart TD + A["开始:语音播报功能"] --> B["配置播报开关、部门范围、播报终端"] + B --> C["前端看板或播报终端启动消息监听"] + C --> D["通过轮询、WebSocket或消息接口检测新订单"] + D --> E{"是否存在未播报的新订单"} + E -- "否" --> C + E -- "是" --> F["生成播报文本"] + F --> G{"当前终端是否允许播放声音"} + G -- "是" --> H["调用浏览器语音或播放音频"] + G -- "否" --> I["提示用户激活播放权限或使用客户端方案"] + H --> J["回写已播报状态或记录播报日志"] + I --> J + J --> K["防止同一订单重复播报"] + K --> C +``` + +### 8 验收标准 1. 新订单出现后,指定终端可听到语音播报。 2. 同一订单不会被重复播报造成干扰。 @@ -294,19 +406,19 @@ 4. 部门播报和全场播报范围符合配置。 5. 电视机或广播设备在生产环境中可稳定使用。 -## 09-需求七:质检 PDA 手机扫码应急功能 +## 需求七:完善质检 PDA 应急方案,在 PDA 设备故障时使用手机扫码保障生产不中断 -### 9.1 需求背景 +### 1 需求背景 -质检 PDA 已有扫码作业能力,但在 PDA 设备故障时,需要使用手机应急完成扫码和质检相关工作。当前功能已开发完成,但生产环境下由于扫码组件安全限制无法使用。 +由质检部门提出,梁宁超核实后上报需求.质检 PDA 已有扫码作业能力,但在 PDA 设备故障时,需要使用手机应急完成扫码和质检相关工作。当前功能已开发完成,但生产环境下由于扫码组件安全限制无法使用。 -### 9.2 功能目标 +### 2 功能目标 1. 确保手机扫码功能在生产环境可正常使用。 2. 在 PDA 故障时,手机可以临时替代 PDA 进行扫码质检作业。 3. 解决扫码组件在生产环境下的安全限制问题。 -### 9.3 问题说明 +### 3 问题说明 扫码组件通常依赖浏览器摄像头权限。生产环境可能存在以下限制: @@ -316,7 +428,7 @@ 4. 扫码组件要求安全上下文,HTTP 环境不可用。 5. 内嵌浏览器或企业微信、钉钉 WebView 权限策略不同。 -### 9.4 解决方向 +### 4 解决方向 1. 将生产环境扫码页面部署到 HTTPS。 2. 配置可信域名和证书,避免直接使用不安全 HTTP 地址调用摄像头。 @@ -324,7 +436,7 @@ 4. 针对手机浏览器、企业微信、钉钉等访问方式分别验证摄像头权限。 5. 保留手工输入条码的兜底方案,避免扫码不可用时业务中断。 -### 9.5 功能要求 +### 5 功能要求 1. 手机页面可打开摄像头并扫码。 2. 扫码结果可回填到质检业务流程。 @@ -332,7 +444,27 @@ 4. 页面需要适配手机端显示。 5. 扫码权限异常时给出明确提示,例如“请使用 HTTPS 地址访问”或“请允许摄像头权限”。 -### 9.6 验收标准 +### 6 功能实现流程图 + +```mermaid +flowchart TD + A["开始:质检PDA手机扫码应急"] --> B["用户使用手机打开质检扫码页面"] + B --> C{"访问环境是否为HTTPS或安全上下文"} + C -- "否" --> D["提示使用HTTPS地址或可信访问方式"] + C -- "是" --> E["请求摄像头权限"] + E --> F{"用户是否授权摄像头"} + F -- "否" --> G["提示开启摄像头权限并提供手动输入"] + F -- "是" --> H["启动扫码组件识别条码"] + H --> I{"是否扫码成功"} + I -- "否" --> G + I -- "是" --> J["扫码结果回填质检业务单据"] + G --> K["手动输入条码"] + J --> L["调用原有质检业务查询或提交接口"] + K --> L + L --> M["完成质检应急作业并保留PDA原有流程"] +``` + +### 7 验收标准 1. 生产环境手机扫码可正常调用摄像头。 2. 扫码后可完成质检业务操作。 @@ -340,19 +472,103 @@ 4. 摄像头权限失败时有明确提示和手动输入兜底。 5. 不影响 PDA 原有扫码功能。 -## 10-优先级建议 +## 需求八:三楼仓库可视化界面,直观展示各库位状态及整体仓储情况 -| 优先级 | 需求 | 原因 | -| --- | --------------- | ------------------ | -| P2 | 质检 PDA 手机扫码应急功能 | 已开发但生产不可用,影响故障应急能力 | -| P0 | 库存盘点及入库库位选择优化 | 直接影响库存准确性和入库操作 | -| P0 | 默认库位设置功能调整 | 影响仓储配置职责和入库库位逻辑 | -| P0 | 物料编码查询 | 涉及页面多,但收益明确 | -| P1 | 车间派工移动端适配 | 改善现场移动操作效率 | -| P2 | 看板优化 | 影响现场展示和管理效率 | -| P2 | 语音播报 | 需要确认硬件、浏览器和广播接入方案 | +### 1 需求背景 -## 11-实施拆分建议 +由仓库管理提出.三楼仓库目前缺少直观的库位可视化展示能力,仓库人员无法快速了解各库位使用状态、物料分布和整体仓储情况。现有立库查询界面已具备 2D 网格矩阵可视化能力(巷道筛选、状态颜色标识、库位点击查看物料详情、统计面板),可参考该方案为三楼仓库开发类似的可视化界面。 + +### 2 功能目标 + +1. 新增三楼仓库可视化组件,直观展示三楼仓库各库位的实时状态。 +2. 展示三楼仓库整体统计信息,包括总库位数、已占用库位数、空闲库位数、使用率等。 +3. 支持按区域、库位类型、物料等条件筛选库位。 +4. 支持点击库位查看物料详情,包括物料编号、物料名称、图号、规格型号、库存数量等。 +5. 参考立库可视化界面的颜色标识方案,用不同颜色区分库位状态。 + +### 3 界面参考 + +参考现有立库可视化界面(`WarehouseVisualization` 组件)的设计模式: + +1. **统计面板**:顶部展示总库位数、已占用数、空闲数、使用率等关键指标,参考立库的 `el-row` + `el-col` 卡片布局。 +2. **颜色图例**:用不同颜色标识库位状态,参考立库的颜色方案: + - 绿色:有库存(对应立库"有物料有托盘") + - 橙色/黄色:预占或待处理 + - 灰色:空闲库位 + - 红色:异常或禁用 +3. **库位矩阵**:以网格或表格形式展示库位分布,行列对应仓库物理位置。 +4. **库位详情弹窗**:点击库位后弹窗展示物料明细,参考立库的 `el-dialog` 详情弹窗。 +5. **筛选条件**:支持按区域、库位编号、物料编码等条件筛选。 + +### 4 前端要求 + +1. 新增三楼仓库可视化页面,建议放在仓储管理模块下,路径如 `src/views/WarehouseManagement/ThirdFloorWarehouse/`。 +2. 参考立库可视化组件的页面结构:统计卡片 + 图例 + 库位网格矩阵 + 详情弹窗。 +3. 使用 Vue 2 Options API + Element UI,保持与现有代码风格一致。 +4. 库位网格支持点击交互,点击后弹出物料详情。 +5. 支持区域切换或筛选,适配三楼仓库的物理布局(如多个区域或排)。 +6. 统计数据实时计算,支持手动刷新和自动刷新(刷新频率可配置)。 +7. 适配大屏展示,文字清晰、布局不拥挤。 +8. 不引入新的第三方库,不使用 Vue 3 或 Composition API。 + +### 5 后端要求 + +1. 新增三楼仓库库位数据查询接口,返回库位编号、库位状态、所在区域等信息。 +2. 新增三楼仓库库位物料详情查询接口,根据库位编号返回物料信息(物料编号、物料名称、图号、规格型号、库存数量、批次等)。 +3. 接口命名遵循现有规范(如 `仓储管理_三楼仓库库位_查询数据`)。 +4. 如果三楼仓库库位数据已有现成的查询过程,优先复用,必要时补充字段。 +5. 统计数据可由前端根据库位列表计算,也可由后端单独提供汇总接口。 + +### 6 功能实现流程图 + +```mermaid +flowchart TD + A["开始:三楼仓库可视化界面"] --> B["梳理三楼仓库库位数据和物理布局"] + B --> C["后端新增或复用库位查询和物料详情接口"] + C --> D["前端新增三楼仓库可视化页面组件"] + D --> E["页面加载时调用库位查询接口获取全部库位数据"] + E --> F["根据库位数据生成网格矩阵并按状态着色"] + F --> G["顶部展示统计面板:总库位、已占用、空闲、使用率"] + G --> H["用户点击某个库位"] + H --> I{"库位是否有物料"} + I -- "是" --> J["弹出物料详情弹窗:物料编号、名称、图号、型号、数量等"] + I -- "否" --> K["弹出库位信息弹窗:库位编号、状态、区域"] + J --> L["用户关闭弹窗或继续操作"] + K --> L + L --> M{"是否切换区域或筛选条件"} + M -- "是" --> N["按筛选条件重新查询库位数据"] + N --> F + M -- "否" --> O{"是否手动刷新或自动刷新触发"} + O -- "是" --> E + O -- "否" --> L +``` + +### 7 验收标准 + +1. 三楼仓库可视化页面可正常加载并展示所有库位。 +2. 不同状态的库位用不同颜色区分,图例说明清晰。 +3. 统计面板数据与实际库位状态一致。 +4. 点击有物料的库位可查看物料详情。 +5. 点击空闲库位可查看库位基本信息。 +6. 区域筛选和条件筛选功能正常。 +7. 刷新数据后页面状态更新正确。 +8. 大屏展示布局合理,文字清晰可读。 +9. 不影响现有立库可视化功能。 + +## 03-优先级建议 + +| 优先级 | 需求 | 原因 | +| --- | --------------- | ----------------------------------------- | +| P2 | 质检 PDA 手机扫码应急功能 | 已开发但生产不可用,影响故障应急能力,即使PDA设备故障也可手动输入不影响现场生产 | +| P0 | 库存盘点及入库库位选择优化 | 直接影响库存准确性和入库操作,现场急要 | +| P0 | 默认库位设置功能调整 | 影响仓储配置职责和入库库位逻辑,现场急要 | +| P0 | 物料编码查询 | 涉及页面多,但收益明确,现场急要 | +| P1 | 三楼仓库可视化界面 | 参考立库已有方案,可快速实现,提升仓库管理直观性 | +| P1 | 车间派工移动端适配 | 改善现场移动操作效率,现场提出,未经过确认需要 | +| P2 | 看板优化 | 影响现场展示和管理效率,需求还不明确 | +| P2 | 语音播报 | 需要确认硬件、浏览器和广播接入方案,需求还不明确 | + +## 04-实施拆分建议 ### 第一阶段:库存与查询基础能力 @@ -360,6 +576,7 @@ 2. 物料编码查询补充。 3. 物料系列字段和库存盘点筛选。 4. 物料入库库位过滤。 +5. 三楼仓库可视化界面(参考立库可视化组件)。 ### 第二阶段:移动端与应急能力 @@ -373,7 +590,7 @@ 3. 现有看板数据口径调整。 4. 新订单语音播报试点。 -## 12-待确认事项 +## 05-待确认事项 1. 默认库位设置新组件归属菜单:仓储管理、基础数据,或单独配置模块。 2. “没有默认库存”与“没有库存库位”的业务定义是否一致。 @@ -384,8 +601,11 @@ 7. 语音播报使用电视机网页播放,还是接入全场广播硬件。 8. 手机扫码生产环境访问方式:HTTPS 域名、内网 IP、企业微信、钉钉或普通浏览器。 9. 语音播报和扫码功能是否需要新增系统配置表。 +10. 三楼仓库的物理布局和库位编码规则(区域划分、行列定义)。 +11. 三楼仓库库位状态分类是否与立库一致,还是需要单独定义(如是否有"预占"、"异常"等状态)。 +12. 三楼仓库可视化是否需要自动刷新,刷新频率多少。 -## 13-风险说明 +## 06-风险说明 1. 默认库位、库存库位、入库库位逻辑如果口径不统一,可能导致入库误选库位。 2. 物料编码查询涉及页面多,需要避免漏改导出和弹窗查询。 @@ -393,9 +613,18 @@ 4. 看板数据口径需与业务部门确认,否则容易出现“页面正确但业务理解不一致”的问题。 5. 浏览器语音自动播放和摄像头扫码都受 HTTPS、安全策略、设备权限影响,必须在生产环境实测。 6. 全场广播接入可能涉及硬件、网络、音频设备,不应只按前端功能估算工作量。 +7. 三楼仓库库位数据如果与立库数据结构差异较大,可能需要单独设计接口和前端组件,复用程度需评估。 -## 14-文档备注 +## 07-文档备注 本次变更为新增需求文档,未修改业务代码。 修改人:Ld 修改时间:2026-06-29 10:29:16 + +补充内容:为 7 项需求分别增加功能实现流程图。 + +修改人:Ld 修改时间:2026-06-29 14:24:36 + +补充内容:新增需求八"三楼仓库可视化界面",参考立库查询界面设计,优先级 P1,纳入第一阶段实施。同步更新优先级建议、实施拆分、待确认事项和风险说明。 + +修改人:Ld 修改时间:2026-06-30 diff --git a/docs/三楼仓库可视化/三楼仓库可视化界面设计方案.md b/docs/三楼仓库可视化/三楼仓库可视化界面设计方案.md new file mode 100644 index 00000000..011ef46a --- /dev/null +++ b/docs/三楼仓库可视化/三楼仓库可视化界面设计方案.md @@ -0,0 +1,919 @@ +# 三楼仓库可视化界面设计方案 + +## 一、背景 + +由仓库管理提出,三楼仓库目前缺少直观的库位可视化展示能力,仓库人员无法快速了解各库位使用状态、物料分布和整体仓储情况。现有立库查询界面已具备 2D 网格矩阵可视化能力(巷道筛选、状态颜色标识、库位点击查看物料详情、统计面板),可参考该方案为三楼仓库开发类似的可视化界面。 + +当前仓库人员判断库位使用情况主要依赖库位管理页面(`LocationManagement`)逐条查询和物料库位页面(`MaterialLocation`)按物料查阅,缺少全局视角的库位状态总览。在盘点、出入库规划、空间利用率评估等场景下,仓库人员需要一屏总览仓库所有库位状态和物料分布,便于快速定位目标库位和发现异常。 + +本次需求优先级为 P1,纳入第一阶段实施。 + +
+ +## 二、现状核对 + +### 2.1 已有立库可视化组件 + +主组件文件: + +- `src/views/WarehouseManagement/WarehouseVisualization/index.vue` +- 组件名:`WarehouseVisualizationSystem` + +已实现功能: + +- 按 4 个巷道加载立库数据,接口名为 `GetPositionView` +- 库位矩阵用原生 HTML `` 绘制 +- 4 种库位状态:0=空库位、1=有托盘无物料、2=有物料有托盘、9=锁库 +- 统计信息卡片:总库位数、有物料有托盘数、有托盘无物料数、空闲库位数、使用率、数据行数 +- 支持按行-层筛选、分页显示 +- 点击状态为 2 的库位调用 `StockDetail(rowLayer, column)` 查询 `StockDetailView` 获取物料明细 +- 点击非 2 状态库位弹出库位详情弹窗 +- 支持文字/图标两种显示模式切换 +- 使用独立的立库数据库服务入口(`ExecDatabase1`,走 `config.js` 中的 `url1`) + +辅助组件文件: + +- `src/views/WarehouseVisualization/index.vue` +- 组件名:`WarehouseVisualization` +- 纯展示组件,通过 `props` 接收 `warehouseData` + +### 2.2 已有仓储数据页面 + +| 页面 | 路径 | 功能 | +| --- | --- | --- | +| 库位管理 | `WarehouseManagement/LocationManagement/index.vue` | 库位增删改查,接口 `仓储管理_库位_查询` | +| 物料库位 | `WarehouseManagement/MaterialLocation/index.vue` | 按物料查库位,接口 `仓储管理_物料库位_查询数据` | +| 库存查询 | `WarehouseManagement/InventoryQuery/index.vue` | 库存汇总查询,接口 `仓储管理_库存查询_查询` | +| 库存盘点 | `WarehouseManagement/InventoryCheck/index.vue` | 盘点数据查询 | +| 仓储汇总 | `WarehouseManagement/WarehouseSummary/index.vue` | 看板式统计汇总 | + +### 2.3 接口调用模式 + +仓储管理模块所有页面的 API 调用均内联在 `.vue` 组件中,通过 `this.CreateData()` + `this.ExecDatabase()` 构造请求参数并调用后端,无独立 API 文件。接口命名遵循 `模块_子模块_操作` 格式。 + +立库可视化走独立的 `ExecDatabase1`(连接立库数据库 `url1`),三楼仓库数据走主业务数据库(`ExecDatabase`),两者数据源不同。 + +### 2.4 数据差异 + +| 对比项 | 立库 | 三楼仓库 | +| --- | --- | --- | +| 数据服务 | 独立志库数据库(`url1:10006`) | 主业务数据库(`url:8030`) | +| 库位编码 | 行-列-层 三段式(如 `03-12-01`) | 待确认(需求文档待确认事项第 10 条) | +| 调用方法 | `ExecDatabase1` | `ExecDatabase` | +| 库位状态 | 0=空、1=有盘无物、2=有物有盘、9=锁 | 待确认(需求文档待确认事项第 11 条) | +| 物理布局 | 巷道-行-列-层 四维结构 | 待确认(需求文档待确认事项第 10 条) | + +## 三、设计原则 + +1. 参考立库可视化组件的页面结构和交互模式(统计卡片 + 图例 + 库位网格矩阵 + 详情弹窗),复用成熟的交互设计,降低用户学习成本。 +2. 三楼仓库数据走主业务数据库(`ExecDatabase`),不走立库独立服务(`ExecDatabase1`),与库位管理、物料库位、库存盘点等仓储页面使用同一数据源。 +3. 接口命名遵循项目现有规范(如 `仓储管理_三楼仓库库位_查询数据`)。 +4. 使用 Vue 2 Options API + Element UI,保持与现有代码风格一致。 +5. 不引入新的第三方库,不使用 Vue 3 或 Composition API。 +6. 样式与立库可视化保持一致的设计语言(颜色方案、卡片风格、单元格交互),但库位布局和状态分类根据三楼仓库实际业务定义。 +7. 库位数据查询和物料详情查询走标准后端接口名,前端不直接拼 SQL,与立库组件中 `StockDetail` 直接构造 SQL 的做法不同,降低前后端耦合。 + +
+ +## 四、前端页面结构设计 + +### 4.1 页面总览 + +新增三楼仓库可视化页面,路径:`src/views/WarehouseManagement/ThirdFloorWarehouse/index.vue` + +页面整体采用标准的 `div.app-container > el-card` 布局,主体包含以下区域: + +1. 顶部筛选与操作区 +2. 统计信息卡片区 +3. 状态图例区 +4. 三楼仓库库位网格矩阵区 +5. 分页区 +6. 库位详情弹窗 +7. 物料信息弹窗 + +### 4.2 顶部筛选与操作区 + +参考立库可视化的筛选区布局,但筛选维度调整为三楼仓库的实际布局维度。 + +#### 4.2.1 区域筛选 + +控件类型:`el-select` + +用途:三楼仓库按物理区域划分(如 A 区、B 区、C 区等,具体区域名称需现场确认)。 + +数据来源:页面初始化时从库位数据中自动提取去重,或后端返回区域字典。 + +选项生成规则: + +- 从库位查询结果中提取 `区域` 字段 +- 自动去重 +- 按区域编码或名称排序 + +#### 4.2.2 库位类型筛选 + +控件类型:`el-select` + +可选项(具体需现场确认): + +- 全部 +- 有库存 +- 空闲 +- 预占/待处理 +- 异常/禁用 + +用途:按库位状态快速筛选关注类别的库位。 + +#### 4.2.3 库位编号搜索 + +控件类型:`el-input` + +用途:直接输入库位编号定位到对应库位。 + +交互: + +- 输入库位编号后,点击搜索,矩阵中匹配的库位高亮显示 +- 支持模糊匹配 + +#### 4.2.4 操作按钮 + +| 按钮 | 类型 | 作用 | +| --- | --- | --- | +| 搜索 | `el-button type="primary"` | 按筛选条件重新查询库位数据 | +| 重置 | `el-button type="default"` | 清空所有筛选条件,恢复全局视图 | +| 刷新数据 | `el-button type="success"` | 重新调用后端接口获取最新数据 | +| 自动刷新开关 | `el-switch` | 控制定时自动刷新(默认关闭) | + +#### 4.2.5 显示模式切换 + +控件类型:`el-switch` + +两种模式: + +- 显示文字:每个库位格显示状态简称(如 `存`、`空`、`预`、`异`) +- 显示图标:每个库位格显示对应 Element UI 图标 + +### 4.3 统计信息卡片区 + +参考立库可视化的 `el-row + el-col` 卡片布局,展示以下 6 项指标: + +| 序号 | 统计项 | 计算方式 | 颜色 | +| --- | --- | --- | --- | +| 1 | 总库位数 | 当前加载的库位总数 | `#303133` | +| 2 | 有库存 | 状态为"有库存"的库位数 | `#4caf50`(绿色) | +| 3 | 预占/待处理 | 状态为"预占"的库位数 | `#ff9800`(橙色) | +| 4 | 空闲库位 | 状态为"空闲"的库位数 | `#e0e0e0`(灰色) | +| 5 | 异常/禁用 | 状态为"异常"的库位数 | `#f56c6c`(红色) | +| 6 | 使用率 | `(有库存 + 预占) / 总库位数 * 100%` | `#2196f3`(蓝色) | + +布局:`el-row :gutter="10"`,每项占 `el-col :span="4"`。 + +统计计算方式: + +- 前端根据库位列表数据实时计算 +- 支持筛选后重新统计(筛选后统计数字反映当前筛选结果) + +### 4.4 状态图例区 + +参考立库可视化图例,居中展示库位状态颜色含义: + +| 颜色 | 含义 | 文字简称 | 图标 | +| --- | --- | --- | --- | +| 绿色 `#4caf50` | 有库存 | 存 | `el-icon-box` | +| 橙色 `#ff9800` | 预占或待处理 | 预 | `el-icon-time` | +| 灰色 `#e0e0e0` | 空闲库位 | 空 | `el-icon-minus` | +| 红色 `#f56c6c` | 异常或禁用 | 异 | `el-icon-warning` | +| 蓝色边框 `#2196f3` | 当前选中库位 | — | — | + +说明: + +- 具体状态分类需与仓库现场确认(待确认事项第 11 条) +- 如果三楼仓库不需要"预占"和"异常"状态,可简化为三种状态(有库存、空闲、选中) +- 如果三楼仓库与立库状态分类一致,可直接复用立库的 4 状态方案(0=空、1=盘无物、2=物有盘、9=锁),但建议重新命名以贴合三楼仓库业务 + +### 4.5 库位网格矩阵区 + +参考立库可视化组件使用原生 `
` 绘制矩阵的方案。 + +#### 4.5.1 矩阵布局 + +三楼仓库的物理布局需现场确认(待确认事项第 10 条),本设计按以下原则适配: + +- 如果三楼仓库按"排-列"二维布局:每行对应一排,每列对应一个列号 +- 如果三楼仓库按"区域-排-列"三维布局:区域通过顶部筛选切换,每个区域内按"排-列"二维展示 +- 如果三楼仓库按不规则布局:可按库位编号分组展示,或按物理位置映射到网格 + +矩阵结构: + +```html +
+ + + + + + + + + + + + +
排/行号{{ col }}
{{ row['行标识'] }} +
+ {{ getStatusText(row[col].状态) }} + +
+ {{ getStatusDescription(row[col].状态) }} +
+
+
+``` + +#### 4.5.2 单元格数据结构 + +每个库位单元格的数据结构建议如下: + +```javascript +{ + '行标识': 'A-01', // 行/排标识 + 1: { // 列号对应的库位信息 + 库位编号: 'A-01-01', + 库位名称: 'A-01-01', + 状态: 0, // 0=空闲, 1=预占, 2=有库存, 3=异常 + 区域: 'A区' + }, + 2: { + 库位编号: 'A-01-02', + 库位名称: 'A-01-02', + 状态: 2, + 区域: 'A区' + } + // ... +} +``` + +说明: + +- 矩阵数据结构参考立库 `warehouseData` 的组织方式(行标识 + 列号映射),但每个单元格从简单状态值扩展为包含 `库位编号`、`库位名称`、`状态`、`区域` 的对象 +- 与立库组件中单元格仅存储状态数字值(`0/1/2/9`)相比,三楼仓库单元格存储更丰富的信息,便于点击时直接获取库位编号查询物料明细 + +#### 4.5.3 单元格交互效果 + +参考立库可视化组件的交互设计: + +- 鼠标悬停:单元格放大(`transform: scale(1.1)`)并显示状态说明浮层 +- 点击选中:蓝色边框高亮选中库位 +- 选中后高亮当前行和列 + +### 4.6 分页区 + +参考立库分页方案,当库位行数较多时支持分页显示: + +- 分页针对"行数据",不是单元格 +- 每页可选条数:`5`、`8`、`10`、`15` +- 布局:`total, sizes, prev, pager, next, jumper` + +### 4.7 库位详情弹窗 + +点击非"有库存"状态的库位时弹出,参考立库的库位详情弹窗但信息更丰富。 + +弹窗标题:`库位详情 - {库位编号}` + +弹窗内容(使用 `el-descriptions` 组件): + +| 字段 | 数据来源 | 说明 | +| --- | --- | --- | +| 库位编号 | 行数据 | 当前点击的库位编号 | +| 库位名称 | 行数据 | 库位显示名称 | +| 区域 | 行数据 | 所属区域 | +| 当前状态 | 行数据 | 状态中文说明 | +| 状态描述 | 前端映射 | 状态对应的业务说明 | +| 最后更新时间 | 后端接口 | 该库位最近一次库存变动时间(需后端支持) | + +弹窗底部操作按钮: + +| 按钮 | 作用 | +| --- | --- | +| 关闭 | 关闭弹窗 | + +### 4.8 物料信息弹窗 + +点击"有库存"状态的库位时弹出,参考立库的物料信息弹窗。 + +弹窗标题:`库位物料信息 - {库位编号}` + +弹窗内容(使用 `el-table` 组件): + +| 列名 | 字段 | 宽度 | 说明 | +| --- | --- | --- | --- | +| 物料编号 | `物料编号` | 150 | 显示溢出省略 | +| 物料名称 | `物料名称` | 120 | 显示溢出省略 | +| 图号 | `图号` | 150 | 显示溢出省略 | +| 规格型号 | `规格型号` | 150 | 显示溢出省略 | +| 库存数量 | `库存数量` | 100 | 右对齐,大于 0 绿色、等于 0 红色,保留 3 位小数,下方显示单位 | +| 批次 | `批次` | 120 | 显示溢出省略 | + +弹窗底部操作按钮: + +| 按钮 | 作用 | +| --- | --- | +| 关闭 | 关闭弹窗 | + +数据来源:调用后端接口 `仓储管理_三楼仓库库位物料_查询数据`,传入库位编号。 + +### 4.9 自动刷新 + +仓储汇总看板(`WarehouseSummary`)已有 1 分钟定时刷新的先例。三楼仓库可视化支持可选的自动刷新: + +- 默认关闭,通过顶部 `el-switch` 开启 +- 刷新频率可选:30 秒、1 分钟、5 分钟 +- 刷新时调用与初始加载相同的后端接口重新查询 +- 刷新期间显示 `v-loading` 加载动画 +- 刷新期间不阻断用户操作 + +
+ +## 五、后端接口设计 + +### 5.1 库位数据查询接口 + +接口名:`仓储管理_三楼仓库库位_查询数据` + +请求类型:`type = '1'`(查询) + +请求参数: + +| 参数名 | 参数类型 | 是否必填 | 说明 | +| --- | --- | --- | --- | +| `区域_check` | int | 否 | 是否传入区域筛选,0=不筛选,1=筛选 | +| `区域` | string | 否 | 区域名称,如 `A区` | +| `库位编号_check` | int | 否 | 是否传入库位编号筛选 | +| `库位编号` | string | 否 | 库位编号,支持模糊匹配 | +| `库位状态_check` | int | 否 | 是否传入状态筛选 | +| `库位状态` | int | 否 | 库位状态值 | + +返回数据结构: + +```javascript +[ + { + '行标识': 'A-01', // 矩阵行标识 + 1: { // 列号 + 库位编号: 'A-01-01', + 库位名称: 'A-01-01', + 状态: 0, // 0=空闲, 1=预占, 2=有库存, 3=异常 + 区域: 'A区' + }, + 2: { + 库位编号: 'A-01-02', + 库位名称: 'A-01-02', + 状态: 2, + 区域: 'A区' + } + // ... + }, + // ... +] +``` + +说明: + +- 返回数据结构与立库 `GetPositionView` 类似,但单元格从简单数字扩展为含库位信息的对象 +- 如果后端返回扁平的库位列表更便于实现,前端也可以在接收到扁平数据后自行转换为矩阵结构(见 5.3 节数据转换说明) +- 后端也可以按立库的方式返回矩阵格式,前端直接渲染 + +备选方案(后端返回扁平列表): + +```javascript +[ + { 库位编号: 'A-01-01', 库位名称: 'A-01-01', 状态: 0, 区域: 'A区', 排: 'A-01', 列: 1 }, + { 库位编号: 'A-01-02', 库位名称: 'A-01-02', 状态: 2, 区域: 'A区', 排: 'A-01', 列: 2 }, + // ... +] +``` + +前端接收到扁平数据后自动生成矩阵(见 5.3 节)。 + +### 5.2 库位物料详情查询接口 + +接口名:`仓储管理_三楼仓库库位物料_查询数据` + +请求类型:`type = '1'`(查询) + +请求参数: + +| 参数名 | 参数类型 | 是否必填 | 说明 | +| --- | --- | --- | --- | +| `库位编号_check` | int | 是 | 固定传 1 | +| `库位编号` | string | 是 | 当前点击的库位编号 | +| `UserID` | string | 是 | 从 Cookie 获取 | +| `ModularID` | string | 是 | 当前路由路径 | + +返回数据结构: + +```javascript +[ + { + 物料编号: '02.009.001.0001', + 物料名称: '齿轮', + 图号: 'LRS3056-001', + 规格型号: 'LRS3056-001-A', + 库存数量: 12.000, + 单位: '台', + 批次: 'BATCH20260601001' + } +] +``` + +说明: + +- 返回字段与立库 `StockDetailView` 对齐(物料编号 mno、物料名称 mname、图号 spec、型号 thao、库存数量 qty、单位 munit、批次 batch),但使用中文字段名以保持与项目命名规范一致 +- 如果后端已在仓储管理相关视图中维护了三楼仓库的物料库存与库位关系,优先复用现有视图或过程 + +### 5.3 数据转换(前端侧) + +如果后端返回扁平的库位列表,前端需要将扁平数据转换为矩阵结构。转换逻辑如下: + +```javascript +// 将扁平库位列表转换为矩阵结构 +transformToMatrix(locationList) { + // 按"排/行标识"分组 + var rowMap = {} + locationList.forEach(function(item) { + var rowKey = item.排 || item.行标识 + if (!rowMap[rowKey]) { + rowMap[rowKey] = { '行标识': rowKey } + } + var colKey = item.列 + rowMap[rowKey][colKey] = { + 库位编号: item.库位编号, + 库位名称: item.库位名称, + 状态: item.状态, + 区域: item.区域 + } + }) + // 转为数组并按行标识排序 + var matrixData = Object.values(rowMap) + matrixData.sort(function(a, b) { + return a['行标识'].localeCompare(b['行标识']) + }) + return matrixData +} +``` + +### 5.4 后端接口复用评估 + +| 已有接口 | 可否复用 | 说明 | +| --- | --- | --- | +| `仓储管理_库位_查询` | 部分复用 | 现有库位管理页查询全部库位,但缺少"状态"字段和矩阵布局信息,需补充或新增三楼仓库专用接口 | +| `仓储管理_物料库位_查询数据` | 作为物料详情备选 | 按物料查库位,可反向使用按库位查物料,但参数和返回字段可能需要调整 | +| `仓储管理_库存查询_查询` | 不直接复用 | 库存查询按物料聚合,与按库位聚合的需求方向不同 | +| `仓储管理_库存盘点_查询` | 参考数据来源 | 库存盘点数据包含物料与库位的对应关系和库存数量,可作为三楼仓库库位状态和物料明细的数据来源 | +| `GetPositionView`(立库) | 不复用 | 立库走独立数据库,数据结构不同 | + +
+ +## 六、data 数据结构设计 + +```javascript +data() { + return { + // ========== 筛选条件 ========== + areaFilter: '', // 区域筛选值 + statusFilter: '', // 状态筛选值 + locationCodeSearch: '', // 库位编号搜索 + areaOptions: [], // 区域下拉选项,从数据动态生成 + statusOptions: [ // 状态下拉选项 + { label: '全部', value: '' }, + { label: '有库存', value: 2 }, + { label: '预占/待处理', value: 1 }, + { label: '空闲', value: 0 }, + { label: '异常/禁用', value: 3 } + ], + + // ========== 自动刷新 ========== + autoRefresh: false, // 自动刷新开关 + refreshInterval: 60, // 刷新间隔(秒) + refreshTimer: null, // 定时器引用 + refreshOptions: [ // 刷新间隔选项 + { label: '30秒', value: 30 }, + { label: '1分钟', value: 60 }, + { label: '5分钟', value: 300 } + ], + + // ========== 分页 ========== + pageCurrent: 1, + pageSize: 8, + + // ========== 矩阵数据 ========== + locationRawData: [], // 后端返回的原始数据(扁平列表) + locationMatrixData: [], // 转换后的矩阵数据 + filteredData: [], // 筛选后的矩阵数据 + displayedData: [], // 当前页显示的矩阵数据 + + // ========== 选中与交互状态 ========== + selectedCell: null, // { 行标识, 列号, 库位信息 } + highlightedRow: null, // 当前高亮行 + hoveredCell: null, // 当前悬停单元格 + + // ========== 统计信息 ========== + statistics: { + total: 0, + withStock: 0, + preOccupied: 0, + empty: 0, + abnormal: 0, + usageRate: 0 + }, + + // ========== 弹窗 ========== + detailDialogVisible: false, // 库位详情弹窗 + detailInfo: {}, // 当前弹窗展示的库位信息 + materialDialogVisible: false, // 物料信息弹窗 + materialLoading: false, + materialList: [], // 当前库位的物料列表 + materialLocationCode: '', // 当前查询的库位编号 + + // ========== 显示设置 ========== + showCellText: 'text', // 'text' 或 'icon' + loading: false, + lastUpdateTime: '' + } +} +``` + +
+ +## 七、methods 核心方法设计 + +### 7.1 数据加载与转换 + +```javascript +// 加载三楼仓库库位数据 +loadLocationData() { + this.loading = true + var param = [] + param[0] = ['区域_check', this.areaFilter ? 1 : 0] + param[1] = ['区域', this.areaFilter] + param[2] = ['库位编号_check', this.locationCodeSearch ? 1 : 0] + param[3] = ['库位编号', this.locationCodeSearch] + param[4] = ['库位状态_check', this.statusFilter !== '' ? 1 : 0] + param[5] = ['库位状态', this.statusFilter] + var Data = this.CreateData('1', '仓储管理_三楼仓库库位_查询数据', param) + this.getTable(Data).then(response => { + this.locationRawData = response.data || [] + this.locationMatrixData = this.transformToMatrix(this.locationRawData) + this.filteredData = this.locationMatrixData + this.updateStatistics() + this.updateDisplayedData() + this.updateAreaOptions() + this.updateLastUpdateTime() + this.loading = false + }).catch(() => { + this.loading = false + }) +} + +// 将扁平库位列表转换为矩阵结构 +transformToMatrix(list) { + // 按"排/行标识"分组(同 5.3 节) +} +``` + +### 7.2 统计计算 + +```javascript +updateStatistics() { + var withStock = 0 + var preOccupied = 0 + var empty = 0 + var abnormal = 0 + this.filteredData.forEach(function(row) { + Object.keys(row).forEach(function(key) { + if (key !== '行标识') { + var status = row[key].状态 + if (status === 2) withStock++ + else if (status === 1) preOccupied++ + else if (status === 0) empty++ + else if (status === 3) abnormal++ + } + }) + }) + var total = withStock + preOccupied + empty + abnormal + var usageRate = total > 0 ? (((withStock + preOccupied) / total) * 100).toFixed(1) : 0 + this.statistics = { total, withStock, preOccupied, empty, abnormal, usageRate } +} +``` + +### 7.3 单元格点击交互 + +```javascript +selectLocation(rowKey, colKey, locationInfo) { + this.selectedCell = { 行标识: rowKey, 列号: colKey, 信息: locationInfo } + this.highlightedRow = rowKey + if (locationInfo.状态 === 2) { + // 有库存,查询物料明细 + this.loadMaterialDetail(locationInfo.库位编号) + } else { + // 非有库存状态,显示库位详情 + this.showLocationDetail(locationInfo) + } +} + +// 查询库位物料明细 +loadMaterialDetail(locationCode) { + this.materialLoading = true + this.materialLocationCode = locationCode + var param = [] + param[0] = ['库位编号_check', 1] + param[1] = ['库位编号', locationCode] + var Data = this.CreateData('1', '仓储管理_三楼仓库库位物料_查询数据', param) + this.getTable(Data).then(response => { + this.materialList = response.data || [] + this.materialDialogVisible = true + this.materialLoading = false + }).catch(() => { + this.materialLoading = false + }) +} + +// 显示库位详情 +showLocationDetail(locationInfo) { + this.detailInfo = { + 库位编号: locationInfo.库位编号, + 库位名称: locationInfo.库位名称, + 区域: locationInfo.区域, + 状态: this.getStatusLabel(locationInfo.状态), + 状态描述: this.getStatusDescription(locationInfo.状态) + } + this.detailDialogVisible = true +} +``` + +### 7.4 状态映射方法 + +```javascript +// 获取状态显示文字 +getStatusLabel(status) { + var map = { 0: '空', 1: '预', 2: '存', 3: '异' } + return map[status] || '未知' +} + +// 获取状态完整描述 +getStatusDescription(status) { + var map = { + 0: '空闲库位,可存放物料', + 1: '预占或待处理,库位已被预留', + 2: '有库存,库位上存放有物料', + 3: '异常或禁用,库位不可使用' + } + return map[status] || '未知状态' +} + +// 获取状态图标类名 +getStatusIcon(status) { + var map = { + 0: 'el-icon-minus', + 1: 'el-icon-time', + 2: 'el-icon-box', + 3: 'el-icon-warning' + } + return map[status] || 'el-icon-question' +} +``` + +### 7.5 自动刷新 + +```javascript +// 切换自动刷新 +handleAutoRefreshChange(val) { + if (val) { + this.startAutoRefresh() + } else { + this.stopAutoRefresh() + } +} + +startAutoRefresh() { + this.stopAutoRefresh() + var self = this + this.refreshTimer = setInterval(function() { + self.loadLocationData() + }, this.refreshInterval * 1000) +} + +stopAutoRefresh() { + if (this.refreshTimer) { + clearInterval(this.refreshTimer) + this.refreshTimer = null + } +} +``` + +
+ +## 八、页面样式设计 + +参考立库可视化组件的样式方案,保持一致的设计语言。 + +### 8.1 核心样式类 + +| 类名 | 用途 | 参考来源 | +| --- | --- | --- | +| `.warehouse-table` | 矩阵表格 | 立库 `.warehouse-table` 复用 | +| `.location-cell` | 库位单元格 | 立库 `.warehouse-cell` 调整命名 | +| `.status-0` | 空闲库位灰色 | 立库 `.status-0` 复用 | +| `.status-1` | 预占橙色 | 立库 `.status-1`(橙色),新增 | +| `.status-2` | 有库存绿色 | 立库 `.status-2` 复用 | +| `.status-3` | 异常红色 | 新增,区别于立库锁库蓝色 | +| `.selected-cell` | 选中蓝色边框 | 立库 `.selected-cell` 复用 | +| `.highlighted-row` | 行高亮 | 立库 `.highlighted-row` 复用 | +| `.cell-tooltip` | 悬浮提示 | 立库 `.cell-tooltip` 复用 | +| `.legend-color` | 图例色块 | 立库 `.legend-color` 复用 | + +### 8.2 大屏适配 + +参考立库可视化组件的响应式断点: + +```scss +// 全屏大屏:默认 1920px +.warehouse-table { + min-width: 1200px; + .location-cell { min-width: 40px; height: 40px; } +} + +// 中等屏幕:1400px 以下 +@media (max-width: 1400px) { + .warehouse-table { + min-width: 900px; + .location-cell { min-width: 35px; height: 35px; } + } +} + +// 小屏幕:992px 以下 +@media (max-width: 992px) { + .warehouse-table { + min-width: 700px; + .location-cell { min-width: 30px; height: 30px; } + } +} +``` + +### 8.3 与立库样式的差异 + +| 差异项 | 立库 | 三楼仓库 | +| --- | --- | --- | +| 异常状态颜色 | 锁库=天蓝色 `skyblue` | 异常=红色 `#f56c6c` | +| 状态数量 | 4 种 | 3-4 种(取决于现场确认) | +| 单元格内容 | 纯状态值 | 含库位信息的对象 | + +
+ +## 九、功能实现流程 + +```mermaid +flowchart TD + A["开始:三楼仓库可视化"] --> B["页面 created 调用 loadLocationData"] + B --> C["构造请求参数:区域、库位编号、状态"] + C --> D["调用 仓储管理_三楼仓库库位_查询数据"] + D --> E{"后端返回数据格式"} + E -- "矩阵格式" --> F["直接渲染矩阵"] + E -- "扁平列表" --> G["前端调用 transformToMatrix 转换为矩阵"] + F --> H["更新统计卡片、图例、矩阵"] + G --> H + H --> I["用户操作"] + I --> J{"操作类型"} + J -- "切换区域" --> K["更新 areaFilter 并重新 loadLocationData"] + J -- "切换状态筛选" --> L["前端筛选 filteredData 并重新统计"] + J -- "输入库位编号搜索" --> M["高亮匹配库位"] + J -- "切换显示模式" --> N["切换文字/图标"] + J -- "点击库位" --> O{"库位状态"} + O -- "有库存" --> P["调用 仓储管理_三楼仓库库位物料_查询数据"] + P --> Q["弹出物料信息表格弹窗"] + O -- "非有库存" --> R["弹出库位详情描述弹窗"] + J -- "开启自动刷新" --> S["启动定时器,按间隔重新 loadLocationData"] + S --> I + K --> H + L --> H +``` + +
+ +## 十、待确认事项 + +| 序号 | 事项 | 影响 | 建议 | +| --- | --- | --- | --- | +| 1 | 三楼仓库的物理布局和库位编码规则 | 决定矩阵行列定义和编码规则 | 需仓库现场确认区域划分、排/列号规则 | +| 2 | 库位状态分类是否与立库一致 | 决定状态数量、颜色和业务含义 | 建议与仓库确认是否需要"预占"和"异常"状态 | +| 3 | 自动刷新频率 | 刷新频率影响服务器压力 | 建议默认 1 分钟,大屏场景可配置 | +| 4 | 后端是否可返回矩阵格式数据 | 影响前端转换复杂度 | 建议后端返回扁平列表,前端转换为矩阵,职责更清晰 | +| 5 | 库位数据是否与立库共用表还是独立表 | 影响后端接口是否复用 | 需后端确认三楼仓库库位数据所在表 | +| 6 | 是否需要导出功能 | 需求文档未提及,但立库已预留 | 建议本期暂不实现,预留后续扩展 | +| 7 | 三楼仓库库位数量规模 | 影响是否需要分页和性能优化 | 需现场确认库位总数,若少于 100 个可一屏展示不分页 | + +
+ +## 十一、影响范围 + +### 11.1 新增文件 + +| 文件 | 说明 | +| --- | --- | +| `src/views/WarehouseManagement/ThirdFloorWarehouse/index.vue` | 三楼仓库可视化页面组件 | + +### 11.2 新增后端接口 + +| 接口名 | 说明 | +| --- | --- | +| `仓储管理_三楼仓库库位_查询数据` | 查询三楼仓库库位列表及状态 | +| `仓储管理_三楼仓库库位物料_查询数据` | 按库位编号查询物料明细 | + +### 11.3 不受影响 + +- 立库可视化组件 `WarehouseVisualization` 不受影响 +- 库位管理 `LocationManagement` 不受影响 +- 物料库位 `MaterialLocation` 不受影响 +- 其他仓储业务页面不受影响 + +
+ +## 十二、验收清单 + +| 序号 | 验收项 | 验收方式 | +| --- | --- | --- | +| 1 | 三楼仓库可视化页面可正常加载并展示所有库位 | 打开页面,确认矩阵展示正常 | +| 2 | 不同状态的库位用不同颜色区分,图例说明清晰 | 检查图例与矩阵颜色对应 | +| 3 | 统计面板数据与实际库位状态一致 | 手工统计库位数量与面板数据对比 | +| 4 | 点击有库存的库位可查看物料详情 | 点击绿色库位,弹窗显示物料编号、名称、图号、库存数量等 | +| 5 | 点击空闲库位可查看库位基本信息 | 点击灰色库位,弹窗显示库位编号、状态说明等 | +| 6 | 区域筛选和状态筛选功能正常 | 切换筛选条件,矩阵刷新并统计更新 | +| 7 | 库位编号搜索可定位到对应库位 | 输入库位编号,点击搜索,目标库位高亮 | +| 8 | 刷新数据后页面状态更新正确 | 点击刷新按钮,矩阵重新加载 | +| 9 | 自动刷新开启后定时更新 | 开启自动刷新,等待自动刷新触发,确认数据更新 | +| 10 | 文字/图标两种显示模式切换正常 | 切换显示模式,确认单元格内容变化 | +| 11 | 大屏展示布局合理,文字清晰可读 | 在 1920px 宽度下检查布局和字体 | +| 12 | 不影响现有立库可视化功能 | 切换到立库可视化页面,确认功能正常 | +| 13 | 分页功能正常(如库位行数较多) | 切换分页,确认分页数据正确 | + +
+ +## 十三、风险与回退 + +### 13.1 风险 + +| 风险 | 影响 | 缓解措施 | +| --- | --- | --- | +| 三楼仓库库位数据与立库数据结构差异较大 | 可能需要单独设计接口和前端组件 | 复用立库可视化交互设计模式,仅数据层调整 | +| 库位编码规则未确认 | 矩阵行列定义无法确定 | 先与仓库确认编码规则再开发,避免返工 | +| 库位状态分类未确认 | 状态值和颜色方案无法确定 | 先与仓库确认状态需求再定义映射 | +| 库位数量规模未知 | 影响性能和分页设计 | 预留分页方案,小规模时可一屏展示 | +| 后端接口未就绪 | 前端无法联调 | 前端先用模拟数据开发,接口就绪后对接 | + +### 13.2 回退方式 + +- 该功能为新增页面,不修改现有任何组件 +- 如有问题,直接移除 `ThirdFloorWarehouse` 目录和对应菜单配置即可回退 +- 不影响其他任何仓储页面功能 + +
+ +## 十四、发布步骤 + +1. 后端部署库位查询和物料详情查询接口 +2. 后端配置三楼仓库可视化的菜单数据(路由、菜单名称、图标等) +3. 发布前端代码(`ThirdFloorWarehouse/index.vue`) +4. 清浏览器缓存后进入系统 +5. 在仓储管理菜单下打开三楼仓库可视化页面 +6. 验证库位矩阵展示与仓库实际布局一致 +7. 验证统计卡片数据准确 +8. 验证点击库位可查看物料详情或库位详情 +9. 验证筛选、搜索、刷新、自动刷新等功能正常 +10. 由仓库人员在现场环境实际使用并确认数据正确性 + +
+ +## 十五、实施拆分 + +### 开发步骤 + +| 步骤 | 内容 | 前置依赖 | +| --- | --- | --- | +| 1 | 与仓库确认物理布局、库位编码规则、状态分类 | 无 | +| 2 | 后端新增库位查询和物料详情查询接口 | 步骤 1 | +| 3 | 前端创建 `ThirdFloorWarehouse/index.vue` 页面框架 | 步骤 1 | +| 4 | 实现矩阵数据加载和转换逻辑 | 步骤 2、3 | +| 5 | 实现统计卡片、图例、矩阵渲染 | 步骤 4 | +| 6 | 实现单元格点击交互和弹窗 | 步骤 5 | +| 7 | 实现筛选、搜索、分页功能 | 步骤 5 | +| 8 | 实现自动刷新功能 | 步骤 4 | +| 9 | 大屏适配和样式调优 | 步骤 7 | +| 10 | 联调测试 | 步骤 9 | + +
+ +修改人:Ld 修改时间:2026-06-30 diff --git a/docs/产品报缺/产品报缺补货需求.docx b/docs/产品报缺/产品报缺补货需求.docx new file mode 100644 index 0000000000000000000000000000000000000000..4fecd4cb9c9a6be62577b199aa30cde4f5d60df0 GIT binary patch literal 197757 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 z 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
Qt#w#rF{!ZlvhZ1-JGfa8jI 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 XbJB7AW2JE!ERAq5-jO39bDaMGbY9KS literal 0 HcmV?d00001 diff --git a/docs/工序工价与生产任务审核/MES提交审批到质检入库全链路测试报告.md b/docs/工序工价与生产任务审核/MES提交审批到质检入库全链路测试报告.md new file mode 100644 index 00000000..437eedf0 --- /dev/null +++ b/docs/工序工价与生产任务审核/MES提交审批到质检入库全链路测试报告.md @@ -0,0 +1,235 @@ +# MES 提交审批到质检入库全链路测试报告 + +## 一、测试结论 + +本次测试通过数据库事务方式模拟完整业务链路,链路可以跑通。 + +验证通过的流程为: + +1. MES 工作站工作机端提交生产完成审批。 +2. JY 主系统生产审核组件审核通过。 +3. 原 MES 完工链路继续执行,工序和工艺计划完成数据更新。 +4. PDA 仓库自制件质检入口可查询到待质检数据,并可提交质检。 +5. JY 主系统仓储模块自制件入库确认可查询并完成入库。 +6. 测试全程在事务内执行并最终回滚,未污染正式业务数据。 + +需要注意:自制件最终入库确认入口当前在 JY 主系统仓储模块,不在 PDA 项目的采购件入库页面中;PDA 项目本次验证的是自制件质检入口。 + +## 二、测试环境 + +| 项目 | 内容 | +| --- | --- | +| 测试时间 | 2026-07-06 | +| 数据库服务器 | 192.168.1.27 | +| 数据库 | ERPTOOL_JY_20250826Back | +| MES 工作站项目 | D:\景耀\MES工作站 | +| JY 主系统项目 | D:\景耀\JY1.0 | +| PDA 仓库项目 | D:\景耀\PDA_仓库 6.30 | +| 测试方式 | SQL Server 事务内模拟,最终 ROLLBACK | + +## 三、涉及入口和过程 + +| 环节 | 前端入口 | 后端过程 | +| --- | --- | --- | +| MES 提交审批 | `D:\景耀\MES工作站\src\components\login.vue` | `MES_机加工MES_加工完成整修审核_提交` | +| 系统内审核 | `D:\景耀\JY1.0\src\views\SeikoWorkshop\ProductionCompletionAudit\index.vue` | `机加工MES_加工完成整修审核_审核数据` | +| 原完工链路 | 审核过程内部继续调用 | `设备管理_零件工序_工序完成过程情况_增加数据` | +| PDA 自制件质检查询 | `D:\景耀\PDA_仓库 6.30\src\components\purchasedWareHouse.vue` | `质检管理_订单查询_查询数据`、`质检管理_工序任务_查询数据`、`质检管理_工序信息_查询数据`、`质检管理_分配任务_查询数据` | +| PDA 自制件质检提交 | `D:\景耀\PDA_仓库 6.30\src\components\purchasedWareHouse.vue` | `车间生产管理_质检管理_不合格处理` | +| 自制件入库确认 | `D:\景耀\JY1.0\src\views\WarehouseManagement\PurchasePartsStorage\index.vue` | `仓储管理_自制件入库_查询`、`仓储管理_自制件入库_循环执行` | + +## 四、测试数据 + +| 字段 | 值 | +| --- | --- | +| 工序流水号 | 124831 | +| 工艺计划流水号 | 6584 | +| 工艺任务流水号 | 38671 | +| 订单流水号 | 19278 | +| 订单号 | BHGZ202606250004 | +| 产品名称 | XT40-2-BT40-AMB | +| 零件名称 | 打刀缸 | +| 零件图号 | XT40-2-BT40-BC-G | +| 物料流水号 | 496 | +| 工序 | 改制 | +| 操作者 | 王建荣 | +| 工位号 | C080 | +| 设备 | 半自动双面铣床 | +| 测试完成数量 | 1 | +| 测试货位流水号 | 1 | + +选用该数据的原因:该任务为末道工序,未完成数量为 1 件,具备从完工审核推进到自制件质检和入库确认的完整条件。 + +## 五、测试步骤与结果 + +### 1. MES 工作站提交审批 + +执行过程:`MES_机加工MES_加工完成整修审核_提交` + +关键参数: + +| 参数 | 值 | +| --- | --- | +| 工序流水号 | 124831 | +| 工作者考勤编号 | 6027 | +| 完成数量 | 1 | +| 完成类型 | 1 | +| 录工票人员编号 | 209 | +| 工位号 | C080 | +| 开始时间 | 2026-07-06 08:30:00 | +| 结束时间 | 2026-07-06 08:40:00 | + +结果: + +| 字段 | 值 | +| --- | --- | +| result | 1 | +| 审核流水号 | 10 | + +结论:MES 工作站提交审批成功,审核记录可以生成。 + +### 2. JY 主系统审核通过 + +执行过程:`机加工MES_加工完成整修审核_审核数据` + +审核结果: + +| 字段 | 值 | +| --- | --- | +| result | 1 | +| 审核状态 | 审核通过 | +| 审核表开始时间 | 2026-07-06 08:30:00 | +| 审核表结束时间 | 2026-07-06 08:40:00 | +| 工序完成数量 | 1 | +| 工序状态 | 4 | +| 工艺计划完成数量 | 1 | +| 工艺计划考核状态 | 3 | + +结论:审核通过后已继续调用原 MES 完工链路,工序完成和工艺计划完成数据已推进。 + +### 3. PDA 自制件质检查询 + +在审核通过后的事务内,模拟 PDA 页面查询: + +| 查询过程 | 验证结果 | +| --- | --- | +| `质检管理_订单查询_查询数据` | 可查到订单 `19278 / BHGZ202606250004` | +| `质检管理_工序任务_查询数据` | 可查到 `改制-王建荣`,任务流水号 `38671` | +| `质检管理_工序信息_查询数据` | 可查到零件、工序、设备和数量 | +| `质检管理_分配任务_查询数据` | 可查到该工序分配记录 | + +结论:审核通过后,PDA 自制件质检页面的数据查询链路可用。 + +### 4. PDA 自制件质检提交 + +执行过程:`车间生产管理_质检管理_不合格处理` + +关键参数: + +| 参数 | 值 | +| --- | --- | +| 零部件流水号 | 38671 | +| 质检类型代码 | 3 | +| 数量 | 1 | +| 是否合格 | 1 | +| 人员编号 | 5 | +| 不合格数量 | 0 | +| 订单流水号 | 19278 | +| 订单号 | BHGZ202606250004 | +| 质检数量 | 1 | + +结果: + +| 字段 | 值 | +| --- | --- | +| 质检流水号 | 15915 | +| 质检主表记录数 | 1 | +| 待入库单数 | 1 | + +结论:PDA 自制件质检提交成功,并生成自制待入库单。 + +### 5. 自制件入库查询 + +执行过程:`仓储管理_自制件入库_查询` + +查询条件: + +| 参数 | 值 | +| --- | --- | +| 订单号_check | 1 | +| 订单号 | 19278 | +| 零件图号_check | 1 | +| 零件图号 | XT40-2-BT40-BC-G | + +结果: + +| 字段 | 值 | +| --- | --- | +| 工艺计划流水号 | 6584 | +| 物料流水号 | 496 | +| 零件名称 | 打刀缸 | +| 零件图号 | XT40-2-BT40-BC-G | +| 完成数量 | 1 | +| 入库数量 | 0 | +| 本次入库 | 1 | +| 类型 | 自制件 | + +结论:质检后,自制件入库确认列表可以查询到该待入库记录。 + +### 6. 自制件入库确认 + +执行过程:`仓储管理_自制件入库_循环执行` + +关键参数: + +| 参数 | 值 | +| --- | --- | +| 物料流水号组 | 496 | +| 实际到货数量组 | 1 | +| 工艺计划流水号组 | 6584 | +| 入库人员流水号 | 5 | +| 货位流水号组 | 1 | +| 类型组 | 自制件 | +| 批号组 | 0 | + +事务内结果: + +| 字段 | 值 | +| --- | --- | +| 工艺计划入库数量 | 1 | +| 工艺计划考核状态 | 4 | +| 自制件入库记录数 | 1 | +| 货位存量 | 1 | + +结论:自制件入库确认成功,库存与工艺计划入库状态能够更新。 + +### 7. 回滚验证 + +执行 `ROLLBACK TRAN` 后复查: + +| 字段 | 回滚后结果 | +| --- | --- | +| 工序完成数量 | NULL | +| 工序状态 | NULL | +| 工艺计划完成数量 | 0 | +| 工艺计划入库数量 | 0 | +| 工艺计划考核状态 | 2 | +| 审核记录是否存在 | 0 | +| 质检记录是否存在 | 0 | + +结论:测试数据已全部回滚,未污染正式数据。 + +## 六、风险和注意事项 + +1. 本次为数据库事务内模拟测试,验证的是后端过程和页面查询入口对应的业务链路,不等同于人工在浏览器逐按钮点击的 UI 测试。 +2. 自制件最终入库确认入口在 JY 主系统仓储模块 `PurchasePartsStorage`,PDA 项目当前未发现自制件最终入库确认页面。 +3. PDA 项目的 `inbound.vue` 主要覆盖采购件、离线件、车间采购件等入库,不是本次自制件完工质检后的最终入库确认入口。 +4. 若后续要求“全程都在 PDA 完成入库确认”,需要新增或调整 PDA 自制件入库确认页面,并对接 `仓储管理_自制件入库_查询` 和 `仓储管理_自制件入库_循环执行`。 + +## 七、最终结论 + +从 MES 工作站提交生产完成审批,到 JY 主系统审核通过,再到 PDA 自制件质检,最后到 JY 主系统自制件入库确认,数据库业务链路验证通过。 + +本次测试未发现阻断性问题。 + +修改人:Ld 修改时间:2026-07-06 09:14:24; diff --git a/docs/工序工价与生产任务审核/工序工价与生产任务审核开发说明.md b/docs/工序工价与生产任务审核/工序工价与生产任务审核开发说明.md new file mode 100644 index 00000000..79afd59d --- /dev/null +++ b/docs/工序工价与生产任务审核/工序工价与生产任务审核开发说明.md @@ -0,0 +1,423 @@ +# 工序工价与生产任务审核开发说明 + +## 一、需求来源 + +本文档根据桌面需求文件 `工序工价需求文档.docx`、`生产任务审核.docx` 整理,用于指导 JY1.0 前端、接口和数据库开发。 + +## 二、需求范围 + +本次需求分为两组功能: + +1. 工序工价与工时金额:新增工序定价录入、工时统计金额显示、整修记录补助金额。 +2. 生产任务审核:车间工况机完成数量提报或异常报备后,先生成计划员审核单,审核通过后进入原系统后续流程。 + +## 三、现状入口 + +| 功能点 | 现有入口 | 现有接口/过程 | +| --- | --- | --- | +| 工时统计 | `src/views/SeikoWorkshop/WorkingHoursStatistics/index.vue` | `车间生产管理_工人工时统计_查询数据`、`精工车间_员工工时统计_详情_查询数据`、`车间生产管理_设备工时统计_查询数据`、`精工车间_设备工时统计_详情_查询数据` | +| 工艺/工序基础维护 | `src/views/BasicData/WorkshopProcessMaintenance/index.vue` | `工艺名称_查询`、`车间生产管理工艺_基础表_工艺名称_增加数据`、`车间生产管理工艺_基础表_工艺名称_修改名称及简称` | +| 生产任务查询 | `src/views/SeikoWorkshop/ProductionTaskQuery/index.vue` | `精工车间_生成任务_查询数据`、`车间生产管理工艺_追溯加工_查询工序` | +| 整修记录 | `src/views/DeviceManagement/RepairRecord/index.vue` | `设备管理_整修记录_查询` | + +## 四、工序工价功能设计 + +### 4.1 新增独立工序工价维护页面 + +需求中提到现场希望把 9 个工价字段放入已有车间查看工艺组件。考虑现有查看工艺组件偏生产现场查看,字段较多且属于工价管理,建议新增独立页面。 + +建议新增页面: + +```text +src/views/SeikoWorkshop/ProcessPrice/index.vue +``` + +建议新增接口文件: + +```text +src/api/ManufacturingCenter/ProcessPrice.js +``` + +页面结构: + +1. 搜索栏:工序名称、工艺名称、零件名称、图号、启用状态。 +2. 左侧表格:工序列表。 +3. 右侧表格或弹窗:工序工价字段维护。 +4. 操作:查询、新增、编辑、删除、查看历史定价。 + +建议字段: + +| 字段名 | 类型 | 说明 | +| --- | --- | --- | +| 工价流水号 | int | 主键 | +| 工序流水号 | int | 关联 `车间生产管理工艺_零件工序` | +| 工艺计划流水号 | int | 关联生产任务工艺计划 | +| 工序名称 | nvarchar | 页面显示 | +| 计价方式 | nvarchar | 按件、按时、固定金额 | +| 单件工价 | decimal | 按件计价 | +| 单时工价 | decimal | 按工时计价 | +| 准结工价 | decimal | 准结补偿 | +| 难度系数 | decimal | 价格修正 | +| 质量系数 | decimal | 质量修正 | +| 设备系数 | decimal | 设备修正 | +| 生效日期 | datetime | 价格生效时间 | +| 失效日期 | datetime | 价格失效时间 | +| 是否启用 | int | 1 启用,0 停用 | +| 备注 | nvarchar | 说明 | +| 创建人 | nvarchar | 操作者 | +| 创建时间 | datetime | 写入时间 | +| 修改人 | nvarchar | 最后修改人 | +| 修改时间 | datetime | 最后修改时间 | + +> 需求原文提到“9 个字段数据”,实际字段名称需要现场确认。上表先按定价业务补全为可落库方案,开发前应与业务确认 9 个必填字段。 + +### 4.2 工序历史定价 + +新增历史查询能力,用于查看工序价格变更轨迹。 + +建议数据表: + +```text +车间生产管理工艺_工序工价历史记录 +``` + +记录内容: + +| 字段名 | 说明 | +| --- | --- | +| 历史流水号 | 主键 | +| 工价流水号 | 对应当前工价记录 | +| 工序流水号 | 对应工序 | +| 修改前数据 | 可按字段拆列或保存摘要 | +| 修改后数据 | 可按字段拆列或保存摘要 | +| 操作类型 | 新增、编辑、停用 | +| 操作者 | 当前用户 | +| 操作时间 | 当前时间 | + +### 4.3 接口设计 + +新增过程建议: + +| 接口名称 | type | 用途 | +| --- | --- | --- | +| `车间生产管理工艺_工序工价_查询数据` | `11` | 查询工序工价列表 | +| `车间生产管理工艺_工序工价_增加数据` | `12` | 新增工序工价 | +| `车间生产管理工艺_工序工价_编辑数据` | `12` | 编辑工序工价 | +| `车间生产管理工艺_工序工价_删除数据` | `12` | 停用或删除工价 | +| `车间生产管理工艺_工序工价_历史_查询数据` | `11` | 查询历史定价 | + +前端请求继续使用项目统一方式: + +```js +var Data = this.CreateData('11', '车间生产管理工艺_工序工价_查询数据', param, this.pageSize, this.pageCurrent) +this.ExecDatabase(Data).then(response => { + this.tableData = response.data.rows + this.total = response.data.total +}) +``` + +## 五、工时统计金额功能设计 + +### 5.1 页面改造 + +修改页面: + +```text +src/views/SeikoWorkshop/WorkingHoursStatistics/index.vue +``` + +员工工时统计左侧汇总表增加: + +| 新增列 | 说明 | +| --- | --- | +| 工价 | 按所选人员统计周期内匹配工序工价后的平均或汇总工价 | +| 总金额 | 汇总加工金额 | + +员工工时明细表增加: + +| 新增列 | 说明 | +| --- | --- | +| 工价 | 当前工序匹配的有效工价 | +| 金额 | 按 `完成数`、`加工时长` 和计价方式计算 | + +设备工时统计如业务需要同步增加金额列,字段逻辑与员工工时一致,但汇总维度为设备。 + +### 5.2 汇总规则 + +建议后端统一计算金额,前端只展示和汇总,避免不同页面计算规则不一致。 + +计价规则: + +| 计价方式 | 金额计算 | +| --- | --- | +| 按件 | `完成数 * 单件工价 * 难度系数 * 质量系数 * 设备系数` | +| 按时 | `加工时长 / 60 * 单时工价 * 难度系数 * 质量系数 * 设备系数` | +| 固定金额 | `固定工价` | + +表格最后一栏金额汇总可使用 Element UI `show-summary`,也可由后端返回汇总行。为保证分页情况下金额准确,建议后端返回总金额字段,前端展示分页明细和总计。 + +### 5.3 工时修正 + +需求中提到“工时记录与现实不同时可以修改”。建议新增明细行编辑入口,仅允许有权限人员调整。 + +新增字段: + +| 字段名 | 说明 | +| --- | --- | +| 原加工时长 | 系统扫码产生的原始工时 | +| 调整后工时 | 审核后用于结算的工时 | +| 工时调整原因 | 必填 | +| 工时调整人 | 当前用户 | +| 工时调整时间 | 当前时间 | + +新增接口: + +| 接口名称 | type | 用途 | +| --- | --- | --- | +| `车间生产管理工艺_工时统计_工时修正_编辑数据` | `12` | 修改工时并记录原因 | +| `车间生产管理工艺_工时统计_工时修正记录_查询数据` | `11` | 查看修正历史 | + +## 六、整修记录补助金额功能设计 + +### 6.1 页面改造 + +修改页面: + +```text +src/views/DeviceManagement/RepairRecord/index.vue +``` + +搜索栏新增: + +| 控件 | 字段 | +| --- | --- | +| `el-input` 或 `el-select` | 报备人 | + +表格新增: + +| 新增列 | 说明 | +| --- | --- | +| 单时补助 | 可编辑,记录每小时补助金额 | +| 总金额 | 自动计算,`工时 * 单时补助` | + +页面新增汇总: + +1. 当前查询条件下的整修工时合计。 +2. 当前查询条件下的补助金额合计。 + +### 6.2 编辑规则 + +1. `单时补助` 必须大于等于 0。 +2. `总金额` 不允许手工编辑,由后端或前端按工时自动计算。 +3. 修改单时补助后写入操作日志。 +4. 导出 Excel 时同步输出 `单时补助` 和 `总金额`。 + +### 6.3 接口设计 + +调整现有查询过程: + +```text +设备管理_整修记录_查询 +``` + +新增入参: + +```text +报备人 +``` + +新增返回字段: + +```text +单时补助 +总金额 +``` + +新增编辑过程: + +| 接口名称 | type | 用途 | +| --- | --- | --- | +| `设备管理_整修记录_单时补助_编辑数据` | `12` | 更新单时补助 | +| `设备管理_整修记录_补助修改记录_查询数据` | `11` | 查询补助修改历史 | + +## 七、生产任务审核功能设计 + +### 7.1 业务流程 + +车间工况机端提报加工完成或异常报备时,先生成审核单。计划员审核通过后,再进入原有后续流程。 + +经现场讨论,取消“不通过打回”功能。如数据不准确,由审核员在审核页面直接修改完成数量、完成时间、异常信息等数据后审核通过。 + +```mermaid +flowchart TD + A["工况机提报完成数量或异常报备"] --> B["生成生产任务审核单"] + B --> C["计划员进入审核页面"] + C --> D{"数据是否准确"} + D -- "准确" --> E["审核通过"] + D -- "不准确" --> F["审核员修改完成数量/完成时间/异常信息"] + F --> E + E --> G["写入原生产任务后续流程"] + G --> H["刷新生产任务/工时/追溯数据"] +``` + +### 7.2 新增审核页面 + +建议新增页面: + +```text +src/views/SeikoWorkshop/ProductionTaskAudit/index.vue +``` + +页面结构: + +1. 搜索栏:提交时间、订单号、零件名称、图号、操作者、审核状态。 +2. 表格:待审核/已审核任务。 +3. 操作:查看、编辑、审核通过。 + +表格字段: + +| 字段名 | 说明 | +| --- | --- | +| 审核流水号 | 主键 | +| 来源类型 | 完工提报、异常报备 | +| 工艺计划流水号 | 关联生产任务 | +| 工序流水号 | 关联工序 | +| 订单号 | 显示 | +| 零件名称 | 显示 | +| 图号 | 显示 | +| 工序 | 显示 | +| 提报完成数量 | 工况机提报数量 | +| 审核完成数量 | 审核员可修改 | +| 提报完成时间 | 工况机提报时间 | +| 审核完成时间 | 审核员可修改 | +| 异常类型 | 异常报备使用 | +| 异常说明 | 异常报备使用 | +| 提报人 | 工况机操作者 | +| 提报时间 | 创建审核单时间 | +| 审核状态 | 待审核、已审核 | +| 审核人 | 当前用户 | +| 审核时间 | 审核通过时间 | +| 审核备注 | 说明 | + +### 7.3 数据表设计 + +建议新增: + +```text +车间生产管理_生产任务审核单 +``` + +关键字段: + +| 字段名 | 类型 | 说明 | +| --- | --- | --- | +| 审核流水号 | int identity | 主键 | +| 来源类型 | nvarchar(20) | 完工提报/异常报备 | +| 业务流水号 | int | 原工况机记录或异常记录 | +| 工艺计划流水号 | int | 生产任务 | +| 工序流水号 | int | 工序 | +| 提报完成数量 | decimal(18, 4) | 原始数量 | +| 审核完成数量 | decimal(18, 4) | 审核后数量 | +| 提报完成时间 | datetime | 原始时间 | +| 审核完成时间 | datetime | 审核后时间 | +| 异常类型 | nvarchar(100) | 异常报备 | +| 异常说明 | nvarchar(500) | 异常报备 | +| 提报人 | nvarchar(50) | 工况机人员 | +| 提报时间 | datetime | 创建时间 | +| 审核状态 | int | 0 待审核,1 已审核 | +| 审核人 | nvarchar(50) | 计划员 | +| 审核时间 | datetime | 审核时间 | +| 审核备注 | nvarchar(500) | 备注 | +| 是否删除 | int | 软删除 | + +### 7.4 接口设计 + +新增过程: + +| 接口名称 | type | 用途 | +| --- | --- | --- | +| `精工车间_生产任务审核_查询数据` | `11` | 审核单分页查询 | +| `精工车间_生产任务审核_编辑数据` | `12` | 审核前修改提报数据 | +| `精工车间_生产任务审核_通过` | `12` | 审核通过并推进原流程 | +| `精工车间_生产任务审核_详情_查询数据` | `11` | 查看单据详情 | + +审核通过过程必须使用事务: + +```text +BEGIN TRAN + 锁定审核单 + 校验审核状态 = 待审核 + 更新审核单审核数量、审核时间、审核人 + 按来源类型调用或复刻原完工/异常报备后续逻辑 + 更新生产任务、工序、工时、异常记录 +COMMIT TRAN +``` + +失败时: + +```text +ROLLBACK TRAN +返回 result = 0 和 msg +``` + +## 八、权限与菜单 + +建议新增菜单: + +| 菜单名称 | 路由 | +| --- | --- | +| 工序工价维护 | `/SeikoWorkshop/ProcessPrice` | +| 生产任务审核 | `/SeikoWorkshop/ProductionTaskAudit` | + +建议权限: + +1. 工序工价维护:仅工艺、财务、车间管理人员可编辑。 +2. 工时修正:仅车间主管或授权计划员可编辑。 +3. 生产任务审核:计划员可审核,车间操作员不可审核自己的提报。 +4. 整修补助编辑:设备管理或车间主管可编辑。 + +## 九、开发步骤 + +1. 与现场确认工序工价 9 个字段的准确名称、类型和必填规则。 +2. 创建工序工价主表、历史表、生产任务审核单表。 +3. 新增工序工价查询、新增、编辑、删除、历史查询存储过程。 +4. 改造工时统计查询过程,返回工价、金额、总金额。 +5. 改造整修记录查询过程,支持报备人筛选,返回单时补助和总金额。 +6. 新增整修记录单时补助编辑过程。 +7. 改造工况机完成提报、异常报备后端逻辑,改为先生成审核单。 +8. 新增生产任务审核查询、编辑、通过过程。 +9. 新增 `ProcessPrice` 页面。 +10. 新增 `ProductionTaskAudit` 页面。 +11. 修改 `WorkingHoursStatistics` 页面,增加工价、金额展示和汇总。 +12. 修改 `RepairRecord` 页面,增加报备人筛选、补助编辑、金额汇总。 +13. 配置菜单和角色权限。 +14. 联调工况机提报、审核通过、生产任务流转、工时统计、整修补助导出。 + +## 十、验收清单 + +| 验收项 | 预期结果 | +| --- | --- | +| 工序工价新增 | 保存成功,列表可查询 | +| 工序工价编辑 | 修改后历史记录可追溯 | +| 历史定价查询 | 能查看同一工序多次价格变更 | +| 工时统计金额 | 明细金额和汇总金额正确 | +| 工时修正 | 调整后工时参与金额计算,并保留原始工时 | +| 整修记录按报备人查询 | 能按报备人过滤数据 | +| 整修补助编辑 | 单时补助保存成功,总金额自动变化 | +| 整修记录导出 | 导出包含单时补助和总金额 | +| 完工提报审核单 | 工况机提交后生成待审核单 | +| 异常报备审核单 | 异常报备后生成待审核单 | +| 审核数据修改 | 审核员可修改完成数量、完成时间 | +| 审核通过 | 通过后进入原生产任务后续流程 | +| 重复审核控制 | 已审核单据不能再次审核 | +| 权限控制 | 未授权用户不能编辑工价、补助或审核 | + +## 十一、风险与待确认项 + +1. 工序工价“9 个字段”的具体字段名未在需求文档中列明,需要业务补充。 +2. 工时金额计算需要确认按件、按时还是混合计价,以及是否区分准结工时。 +3. 工况机端完工和异常报备的现有后续逻辑需要在数据库中定位后再改造,避免绕过原有工时、质检、追溯更新。 +4. 审核员修改完成数量后,是否需要同步影响质检数、不良数、入库可用数,需要业务确认。 +5. 已有历史工时是否需要补算金额,需要确认补算范围。 + +修改人:Ld 修改时间:2026-07-02 13:01:57; diff --git a/docs/工序工价与生产任务审核/工序工价开发说明.md b/docs/工序工价与生产任务审核/工序工价开发说明.md new file mode 100644 index 00000000..c0e3448f --- /dev/null +++ b/docs/工序工价与生产任务审核/工序工价开发说明.md @@ -0,0 +1,248 @@ +# 工序工价开发说明 + +## 一、需求来源 + +本文档根据桌面需求文件 `工序工价需求文档.docx` 整理,用于指导 JY1.0 工序工价、工时金额和整修补助相关开发。 + +## 二、需求范围 + +本需求包含三个目标: + +1. 给工序增加 9 个工价相关字段,并支持录入、维护和历史定价查看。 +2. 工时统计组件增加工价、金额字段,并在汇总栏展示金额合计。 +3. 整修记录模块增加按报备人查询,并增加单时补助、总金额和汇总。 + +## 三、现有入口 + +| 功能点 | 现有入口 | 现有接口/过程 | +| --- | --- | --- | +| 工时统计 | `src/views/SeikoWorkshop/WorkingHoursStatistics/index.vue` | `车间生产管理_工人工时统计_查询数据`、`精工车间_员工工时统计_详情_查询数据`、`车间生产管理_设备工时统计_查询数据`、`精工车间_设备工时统计_详情_查询数据` | +| 工艺/工序基础维护 | `src/views/BasicData/WorkshopProcessMaintenance/index.vue` | `工艺名称_查询`、`车间生产管理工艺_基础表_工艺名称_增加数据`、`车间生产管理工艺_基础表_工艺名称_修改名称及简称` | +| 整修记录 | `src/views/DeviceManagement/RepairRecord/index.vue` | `设备管理_整修记录_查询` | + +## 四、工序工价维护设计 + +### 4.1 页面方案 + +需求原文提到现场希望把 9 个字段加入已有车间查看工艺组件。考虑现有查看工艺组件偏现场查看,字段多且属于价格管理,建议新增独立页面。 + +建议新增页面: + +```text +src/views/SeikoWorkshop/ProcessPrice/index.vue +``` + +建议新增接口文件: + +```text +src/api/ManufacturingCenter/ProcessPrice.js +``` + +页面结构: + +1. 搜索栏:工艺名称、工序名称、零件名称、图号、启用状态。 +2. 数据表格:展示工序工价记录。 +3. 操作列:新增、编辑、停用、历史定价。 +4. 弹窗:维护 9 个工价字段和备注。 + +### 4.2 字段设计 + +需求文档未列出 9 个字段的准确名称,开发前需现场补充确认。建议先按以下字段作为设计草案: + +| 字段名 | 类型 | 说明 | +| --- | --- | --- | +| 工价流水号 | int | 主键 | +| 工序流水号 | int | 关联工序 | +| 工艺计划流水号 | int | 可选,关联生产任务工艺计划 | +| 工序名称 | nvarchar | 页面显示 | +| 计价方式 | nvarchar | 按件、按时、固定金额 | +| 单件工价 | decimal | 按件计价 | +| 单时工价 | decimal | 按工时计价 | +| 准结工价 | decimal | 准结补偿 | +| 难度系数 | decimal | 价格修正 | +| 质量系数 | decimal | 质量修正 | +| 设备系数 | decimal | 设备修正 | +| 生效日期 | datetime | 价格生效时间 | +| 失效日期 | datetime | 价格失效时间 | +| 是否启用 | int | 1 启用,0 停用 | +| 备注 | nvarchar | 说明 | +| 创建人 | nvarchar | 当前用户 | +| 创建时间 | datetime | 写入时间 | +| 修改人 | nvarchar | 最后修改人 | +| 修改时间 | datetime | 最后修改时间 | + +### 4.3 历史定价 + +新增历史记录表: + +```text +车间生产管理工艺_工序工价历史记录 +``` + +历史表记录工价新增、编辑、停用前后的关键数据,支持按工序查看历次定价变化。 + +## 五、接口设计 + +新增过程: + +| 接口名称 | type | 用途 | +| --- | --- | --- | +| `车间生产管理工艺_工序工价_查询数据` | `11` | 分页查询工序工价 | +| `车间生产管理工艺_工序工价_增加数据` | `12` | 新增工价 | +| `车间生产管理工艺_工序工价_编辑数据` | `12` | 编辑工价 | +| `车间生产管理工艺_工序工价_删除数据` | `12` | 停用或删除 | +| `车间生产管理工艺_工序工价_历史_查询数据` | `11` | 查询历史定价 | + +前端继续使用项目统一请求方式: + +```js +var Data = this.CreateData('11', '车间生产管理工艺_工序工价_查询数据', param, this.pageSize, this.pageCurrent) +this.ExecDatabase(Data).then(response => { + this.tableData = response.data.rows + this.total = response.data.total +}) +``` + +## 六、工时统计金额设计 + +修改页面: + +```text +src/views/SeikoWorkshop/WorkingHoursStatistics/index.vue +``` + +员工工时统计汇总表新增: + +| 字段 | 说明 | +| --- | --- | +| 工价 | 当前统计周期匹配的工价信息 | +| 总金额 | 查询条件下人员金额合计 | + +员工工时明细表新增: + +| 字段 | 说明 | +| --- | --- | +| 工价 | 当前工序有效工价 | +| 金额 | 按工价规则计算 | + +建议后端返回金额,前端只展示和汇总,避免分页和多页面计算规则不一致。 + +金额规则建议: + +| 计价方式 | 金额计算 | +| --- | --- | +| 按件 | `完成数 * 单件工价 * 难度系数 * 质量系数 * 设备系数` | +| 按时 | `加工时长 / 60 * 单时工价 * 难度系数 * 质量系数 * 设备系数` | +| 固定金额 | `固定工价` | + +## 七、工时修正设计 + +需求补充提到工时记录与实际不符时可修改。建议在员工工时明细行增加“修正工时”入口。 + +新增字段: + +| 字段名 | 说明 | +| --- | --- | +| 原加工时长 | 系统扫码原始工时 | +| 调整后工时 | 用于金额结算的工时 | +| 工时调整原因 | 必填 | +| 工时调整人 | 当前用户 | +| 工时调整时间 | 当前时间 | + +新增接口: + +| 接口名称 | type | 用途 | +| --- | --- | --- | +| `车间生产管理工艺_工时统计_工时修正_编辑数据` | `12` | 修改工时 | +| `车间生产管理工艺_工时统计_工时修正记录_查询数据` | `11` | 查询修正历史 | + +## 八、整修记录补助设计 + +修改页面: + +```text +src/views/DeviceManagement/RepairRecord/index.vue +``` + +搜索栏新增: + +| 控件 | 字段 | +| --- | --- | +| `el-input` 或 `el-select` | 报备人 | + +表格新增: + +| 字段 | 说明 | +| --- | --- | +| 单时补助 | 可编辑,记录每小时补助金额 | +| 总金额 | 自动计算,`工时 * 单时补助` | + +规则: + +1. 单时补助必须大于等于 0。 +2. 总金额不允许手工编辑。 +3. 修改单时补助时写入修改记录。 +4. 导出 Excel 同步包含单时补助和总金额。 + +调整现有查询过程: + +```text +设备管理_整修记录_查询 +``` + +新增入参: + +```text +报备人 +``` + +新增返回字段: + +```text +单时补助 +总金额 +``` + +新增接口: + +| 接口名称 | type | 用途 | +| --- | --- | --- | +| `设备管理_整修记录_单时补助_编辑数据` | `12` | 更新单时补助 | +| `设备管理_整修记录_补助修改记录_查询数据` | `11` | 查询补助修改历史 | + +## 九、开发步骤 + +1. 与现场确认工序工价 9 个字段的准确名称、类型、必填规则。 +2. 创建工序工价主表和历史表。 +3. 新增工序工价查询、新增、编辑、删除、历史查询过程。 +4. 新增 `ProcessPrice` 页面并配置菜单。 +5. 改造工时统计查询过程,返回工价、金额、总金额。 +6. 修改 `WorkingHoursStatistics` 页面,增加工价、金额展示和汇总。 +7. 新增工时修正过程和修正记录查询。 +8. 改造整修记录查询过程,支持报备人筛选,返回单时补助和总金额。 +9. 修改 `RepairRecord` 页面,增加报备人筛选、补助编辑、金额汇总。 +10. 联调导出、分页、汇总和权限控制。 + +## 十、验收清单 + +| 验收项 | 预期结果 | +| --- | --- | +| 工序工价新增 | 保存成功,列表可查询 | +| 工序工价编辑 | 修改后历史记录可追溯 | +| 历史定价查询 | 能查看同一工序多次价格变更 | +| 工时统计金额 | 明细金额和汇总金额正确 | +| 工时修正 | 调整后工时参与金额计算,并保留原始工时 | +| 整修记录按报备人查询 | 能按报备人过滤数据 | +| 整修补助编辑 | 单时补助保存成功,总金额自动变化 | +| 整修记录导出 | 导出包含单时补助和总金额 | +| 权限控制 | 未授权用户不能编辑工价、工时和补助 | + +## 十一、风险与待确认项 + +1. 工序工价 9 个字段的具体名称未在需求文档中列明。 +2. 工时金额计算需要确认按件、按时还是混合计价。 +3. 准结工时是否参与金额计算需要确认。 +4. 已有历史工时是否需要补算金额需要确认。 +5. 整修补助是否按所有工时计算,还是按有效整修时间计算,需要确认。 + +修改人:Ld 修改时间:2026-07-02 13:05:56; diff --git a/docs/工序工价与生产任务审核/生产任务审核开发说明.md b/docs/工序工价与生产任务审核/生产任务审核开发说明.md new file mode 100644 index 00000000..1cd9f09d --- /dev/null +++ b/docs/工序工价与生产任务审核/生产任务审核开发说明.md @@ -0,0 +1,214 @@ +# 生产任务审核开发说明 + +## 一、需求来源 + +本文档根据桌面需求文件 `生产任务审核.docx` 整理,用于指导 JY1.0 生产任务审核功能开发。 + +## 二、需求范围 + +本需求目标: + +车间工况机端填报完成数量,或进行异常报备时,需要先提交计划员审核。审核通过后,系统才进入原有后续流程。 + +现场讨论结果: + +1. 取消“不通过打回”功能。 +2. 如果提报数据不准确,由审核员直接修改完成数量、完成时间等数据。 +3. 审核员修正后审核通过,再进入系统后续流程。 + +## 三、现有入口 + +| 功能点 | 现有入口 | 现有接口/过程 | +| --- | --- | --- | +| 生产任务查询 | `src/views/SeikoWorkshop/ProductionTaskQuery/index.vue` | `精工车间_生成任务_查询数据` | +| 零件追溯 | `src/views/SeikoWorkshop/ProductionTaskQuery/index.vue` | `车间生产管理工艺_追溯加工_查询工序` | +| 车间派工 | `src/views/SeikoWorkshop/WorkshopAssignment/index.vue` | 派工、取消派工、已派工查询相关过程 | +| 工时统计 | `src/views/SeikoWorkshop/WorkingHoursStatistics/index.vue` | 工人工时、设备工时统计过程 | + +## 四、业务流程 + +```mermaid +flowchart TD + A["工况机提报完成数量或异常报备"] --> B["生成生产任务审核单"] + B --> C["计划员进入审核页面"] + C --> D{"提报数据是否准确"} + D -- "准确" --> E["审核通过"] + D -- "不准确" --> F["审核员修改完成数量/完成时间/异常信息"] + F --> E + E --> G["写入原生产任务后续流程"] + G --> H["刷新生产任务、工时、追溯数据"] +``` + +## 五、新增审核页面 + +建议新增页面: + +```text +src/views/SeikoWorkshop/ProductionTaskAudit/index.vue +``` + +页面结构: + +1. 搜索栏:提交时间、订单号、零件名称、图号、操作者、审核状态。 +2. 数据表格:待审核和已审核任务。 +3. 操作列:查看、编辑、审核通过。 +4. 编辑弹窗:允许审核员修正完成数量、完成时间、异常信息和审核备注。 + +## 六、页面字段 + +| 字段名 | 说明 | +| --- | --- | +| 审核流水号 | 主键 | +| 来源类型 | 完工提报、异常报备 | +| 工艺计划流水号 | 关联生产任务 | +| 工序流水号 | 关联工序 | +| 订单号 | 页面显示 | +| 零件名称 | 页面显示 | +| 图号 | 页面显示 | +| 工序 | 页面显示 | +| 提报完成数量 | 工况机原始提报数量 | +| 审核完成数量 | 审核员可修改 | +| 提报完成时间 | 工况机原始提报时间 | +| 审核完成时间 | 审核员可修改 | +| 异常类型 | 异常报备使用 | +| 异常说明 | 异常报备使用 | +| 提报人 | 工况机操作者 | +| 提报时间 | 创建审核单时间 | +| 审核状态 | 待审核、已审核 | +| 审核人 | 当前审核用户 | +| 审核时间 | 审核通过时间 | +| 审核备注 | 说明 | + +## 七、数据表设计 + +建议新增表: + +```text +车间生产管理_生产任务审核单 +``` + +字段设计: + +| 字段名 | 类型 | 说明 | +| --- | --- | --- | +| 审核流水号 | int identity | 主键 | +| 来源类型 | nvarchar(20) | 完工提报/异常报备 | +| 业务流水号 | int | 原工况机记录或异常记录 | +| 工艺计划流水号 | int | 生产任务 | +| 工序流水号 | int | 工序 | +| 提报完成数量 | decimal(18, 4) | 原始数量 | +| 审核完成数量 | decimal(18, 4) | 审核后数量 | +| 提报完成时间 | datetime | 原始时间 | +| 审核完成时间 | datetime | 审核后时间 | +| 异常类型 | nvarchar(100) | 异常报备 | +| 异常说明 | nvarchar(500) | 异常报备 | +| 提报人 | nvarchar(50) | 工况机人员 | +| 提报时间 | datetime | 创建时间 | +| 审核状态 | int | 0 待审核,1 已审核 | +| 审核人 | nvarchar(50) | 计划员 | +| 审核时间 | datetime | 审核时间 | +| 审核备注 | nvarchar(500) | 备注 | +| 是否删除 | int | 软删除 | + +## 八、接口设计 + +新增过程: + +| 接口名称 | type | 用途 | +| --- | --- | --- | +| `精工车间_生产任务审核_查询数据` | `11` | 审核单分页查询 | +| `精工车间_生产任务审核_编辑数据` | `12` | 审核前修改提报数据 | +| `精工车间_生产任务审核_通过` | `12` | 审核通过并推进原流程 | +| `精工车间_生产任务审核_详情_查询数据` | `11` | 查看单据详情 | + +前端请求示例: + +```js +var Data = this.CreateData('11', '精工车间_生产任务审核_查询数据', param, this.pageSize, this.pageCurrent) +this.ExecDatabase(Data).then(response => { + this.tableData = response.data.rows + this.total = response.data.total +}) +``` + +## 九、审核通过事务 + +审核通过过程必须使用事务,确保审核单和原生产任务流程一致。 + +```text +BEGIN TRAN + 锁定审核单 + 校验审核状态 = 待审核 + 更新审核完成数量、审核完成时间、审核人、审核时间 + 按来源类型执行原完工提报或异常报备后续逻辑 + 更新生产任务、工序、工时、异常记录 +COMMIT TRAN +``` + +失败时: + +```text +ROLLBACK TRAN +返回 result = 0 和 msg +``` + +## 十、前端交互规则 + +1. 待审核状态允许编辑和审核通过。 +2. 已审核状态只允许查看,不允许再次编辑和审核。 +3. 审核完成数量必须大于等于 0。 +4. 审核完成时间不能为空。 +5. 异常报备类型为异常时,异常类型或异常说明按业务要求校验。 +6. 审核通过前需要二次确认。 +7. 审核成功后刷新列表。 + +## 十一、权限与菜单 + +建议新增菜单: + +| 菜单名称 | 路由 | +| --- | --- | +| 生产任务审核 | `/SeikoWorkshop/ProductionTaskAudit` | + +建议权限: + +1. 计划员可审核。 +2. 车间操作员不可审核自己的提报。 +3. 未授权用户只能查看或不可进入页面。 +4. 审核通过后如需修改,必须走管理员修正或数据库审计流程。 + +## 十二、开发步骤 + +1. 定位工况机完成提报和异常报备现有后端逻辑。 +2. 新增生产任务审核单表。 +3. 改造工况机提报逻辑,提交后先生成待审核单,不直接进入后续流程。 +4. 新增审核查询、编辑、通过、详情过程。 +5. 新增 `ProductionTaskAudit` 页面。 +6. 配置菜单和角色权限。 +7. 联调完工提报生成审核单。 +8. 联调异常报备生成审核单。 +9. 联调审核员修改完成数量、完成时间。 +10. 联调审核通过后生产任务、工时、追溯数据更新。 + +## 十三、验收清单 + +| 验收项 | 预期结果 | +| --- | --- | +| 完工提报审核单 | 工况机提交后生成待审核单 | +| 异常报备审核单 | 异常报备后生成待审核单 | +| 审核列表查询 | 可按时间、订单、人员、状态查询 | +| 审核数据修改 | 审核员可修改完成数量、完成时间 | +| 审核通过 | 通过后进入原生产任务后续流程 | +| 重复审核控制 | 已审核单据不能再次审核 | +| 状态同步 | 生产任务、工序、工时、追溯数据一致 | +| 权限控制 | 未授权用户不能审核 | + +## 十四、风险与待确认项 + +1. 工况机端完工和异常报备的现有后续逻辑需要在数据库中定位后再改造。 +2. 审核员修改完成数量后,是否同步影响质检数、不良数、入库可用数,需要业务确认。 +3. 异常报备审核通过后是否立即触发停机、维修、质量等后续流程,需要确认。 +4. 历史已提报数据是否需要补生成审核单,需要确认。 +5. 审核权限是否按角色、人员或菜单按钮控制,需要确认。 + +修改人:Ld 修改时间:2026-07-02 13:05:56; diff --git a/docs/物料库位设置/物料库位功能调整测试报告.md b/docs/物料库位设置/物料库位功能调整测试报告.md new file mode 100644 index 00000000..1250a4f9 --- /dev/null +++ b/docs/物料库位设置/物料库位功能调整测试报告.md @@ -0,0 +1,398 @@ +# 物料库位功能调整测试报告 + +## 一、测试概述 + +测试日期:2026-06-29 + +测试范围: + +- 物料新增/编辑移除库位设置。 +- 物料标准库位维护页面移除编辑能力。 +- 入库时库位选择逻辑调整为:有库存库位优先显示已有库存库位,无库存库位时显示全库位。 +- 数据库脚本可发布性核对。 +- 前端构建验证。 + +测试环境: + +- 工作目录:`D:\景耀\JY1.0` +- 前端技术栈:Vue 2.5.17、Element UI 2.13、Webpack 4 +- 数据库服务器:`192.168.1.27` +- 数据库:`ERPTOOL_JY_20250826Back` + +本次测试未直接执行数据库 ALTER 脚本,仅做只读核对。 + +## 二、测试对象 + +### 2.1 前端文件 + +- `src/views/TechnologyCenter/MaterialMaintain/index.vue` +- `src/views/TechnologyCenter/MaterialQuery/index.vue` +- `src/views/WarehouseManagement/MaterialLocation/index.vue` +- `src/views/WarehouseManagement/PurchasePartsStorage/index.vue` + +### 2.2 SQL 文件 + +- `sql/移除物料标准库位维护.sql` + +### 2.3 文档文件 + +- `docs/物料库位功能调整设计方案.md` +- `docs/物料库位功能调整测试报告.md` + +## 三、测试用例与结果 + +### 3.1 静态残留检查:物料维护与物料库位页面 + +测试目的: + +确认物料新增/编辑页面不再残留库位表单、库位必填校验、默认库位、物料库位编辑调用。 + +执行命令: + +```powershell +rg -n "form\.库位|库位: \[|inventoryLocation|getInventoryLocation|= 2514|货位流水号', this\.form\.库位|仓储管理_物料库位_编辑数据|@row-dblclick=\"changeState\"|changeState\(|confirmEdit\(|cancelEdit\(|submitLocation\(|addLocation\(" src/views/TechnologyCenter/MaterialMaintain/index.vue src/views/TechnologyCenter/MaterialQuery/index.vue src/views/WarehouseManagement/MaterialLocation/index.vue +``` + +测试结果: + +- 命令退出码:`1` +- 输出:无匹配结果 + +结果说明: + +`rg` 在无匹配时返回退出码 `1`,本测试场景表示未发现目标残留代码。检查通过。 + +结论: + +通过。 + +### 3.2 静态逻辑检查:入库库位选择 + +测试目的: + +确认入库页面包含以下关键逻辑: + +- 页面创建时加载全库位。 +- 调用 `仓储管理_库存盘点_查询` 查询已有库存库位。 +- 已有库存库位显示库存数量。 +- 无库存库位 fallback 到全库位。 +- 入库提交仍传递 `货位流水号组`。 + +执行命令: + +```powershell +rg -n "getLocateName\(|locateSource|locateName\.slice|库存:|仓储管理_库存盘点_查询|仓储管理_库位_查询|货位流水号组" src/views/WarehouseManagement/PurchasePartsStorage/index.vue +``` + +测试结果摘要: + +```text +760: this.getLocateName() +1048: getLocateName() { +1050: var Data = this.CreateData('11', '仓储管理_库位_查询', param) +1133: var Data = this.CreateData('11', '仓储管理_库存盘点_查询', param) +1141: label: data[i].货位名称 + '(库存:' + inventory + ')', +1149: this.$set(row, 'locateSource', 'inventory') +1152: this.$set(row, 'locateName', this.locateName.slice()) +1153: this.$set(row, 'locateSource', 'all') +1156: this.getLocateName().then(setAllLocate) +1299: param[5] = ['货位流水号组', locateGroup] +1436: param[4] = ['货位流水号组', locateGroup] +``` + +结果说明: + +关键代码路径均存在: + +- `created()` 中加载全库位。 +- `getLocateName()` 使用 `仓储管理_库位_查询`。 +- `getInventoryLocateName(row)` 使用 `仓储管理_库存盘点_查询`。 +- 有库存库位时设置 `locateSource = 'inventory'`。 +- 无库存库位时使用 `this.locateName.slice()` 设置全库位,并设置 `locateSource = 'all'`。 +- 采购入库、自制件入库提交仍使用 `货位流水号组`。 + +结论: + +通过。 + +### 3.3 SQL 脚本静态检查 + +测试目的: + +确认 SQL 脚本包含目标存储过程,并保留 `@货位流水号` 兼容参数。 + +执行命令: + +```powershell +rg -n "ALTER PROCEDURE|库存管理_物料与货位对照表|货位流水号|货位流水号 = @货位流水号|货位流水号=@货位流水号" sql/移除物料标准库位维护.sql +``` + +测试结果摘要: + +```text +8: 3. 保留 @货位流水号 参数,兼容未同步发布的旧前端调用。 +11:ALTER PROCEDURE [dbo].[物料管理_增加] +13: @货位流水号 int = null, +41:ALTER PROCEDURE [dbo].[物料管理_增加新] +43: @货位流水号 int = null, +105:ALTER PROCEDURE [dbo].[物料管理_编辑] +107: @货位流水号 int = null, +``` + +结果说明: + +- 脚本包含 `物料管理_增加`、`物料管理_增加新`、`物料管理_编辑`。 +- 脚本保留 `@货位流水号` 参数。 +- 未检出 `货位流水号=@货位流水号` 或 `货位流水号 = @货位流水号` 写入语句。 +- 未检出对 `库存管理_物料与货位对照表` 的新增/更新语句。 + +结论: + +通过。 + +### 3.4 数据库对象参数核对 + +测试目的: + +确认目标数据库中相关存储过程和参数存在,为脚本发布与接口兼容提供依据。 + +执行命令: + +```powershell +sqlcmd -S 192.168.1.27 -d ERPTOOL_JY_20250826Back -U sa -P ****** -C -Q "SET NOCOUNT ON; SELECT o.name AS ObjectName, p.name AS ParamName, TYPE_NAME(p.user_type_id) AS TypeName, p.parameter_id FROM sys.objects o LEFT JOIN sys.parameters p ON o.object_id=p.object_id WHERE o.name IN (N'物料管理_增加',N'物料管理_增加新',N'物料管理_编辑',N'仓储管理_物料库位_编辑数据',N'仓储管理_库存盘点_查询',N'仓储管理_库位_查询') ORDER BY o.name,p.parameter_id;" +``` + +测试结果摘要: + +- `仓储管理_库存盘点_查询` 存在,参数包含: + - `@物料名称_check` + - `@物料名称` + - `@图号或型号_check` + - `@图号或型号` + - `@库位_check` + - `@库位` + - `@排序名称` + - `@排序方式` + - `@物料编码_check` + - `@物料编码` +- `仓储管理_库位_查询` 存在,参数包含: + - `@库位_check` + - `@库位` +- `物料管理_增加` 存在,参数包含 `@货位流水号`。 +- `物料管理_增加新` 存在,参数包含 `@货位流水号`。 +- `物料管理_编辑` 存在,参数包含 `@货位流水号`。 +- `仓储管理_物料库位_编辑数据` 存在,参数包含 `@物料流水号`、`@货位流水号`。 + +结果说明: + +数据库对象与前端调用所需过程匹配。`物料管理_增加/增加新/编辑` 仍保留 `@货位流水号` 参数,因此前端传 `货位流水号 = null` 可以作为兼容占位。 + +结论: + +通过。 + +### 3.5 数据库当前过程行为核对 + +测试目的: + +确认目标数据库当前是否已经执行过本次 SQL 调整脚本。 + +执行命令: + +```powershell +sqlcmd -S 192.168.1.27 -d ERPTOOL_JY_20250826Back -U sa -P ****** -C -Q "SET NOCOUNT ON; SELECT o.name AS ObjectName, CASE WHEN m.definition LIKE N'%库存管理_物料与货位对照表%' THEN 1 ELSE 0 END AS TouchMaterialLocationTable, CASE WHEN m.definition LIKE N'%货位流水号=@货位流水号%' OR m.definition LIKE N'%货位流水号 = @货位流水号%' THEN 1 ELSE 0 END AS WritesLocationSerial FROM sys.objects o JOIN sys.sql_modules m ON o.object_id=m.object_id WHERE o.name IN (N'物料管理_增加',N'物料管理_增加新',N'物料管理_编辑',N'仓储管理_物料库位_编辑数据');" +``` + +测试结果: + +```text +ObjectName TouchMaterialLocationTable WritesLocationSerial +仓储管理_物料库位_编辑数据 1 1 +物料管理_编辑 1 1 +物料管理_增加 1 0 +物料管理_增加新 1 0 +``` + +结果说明: + +目标数据库当前仍是旧过程行为: + +- `物料管理_增加`、`物料管理_增加新` 仍接触 `库存管理_物料与货位对照表`。 +- `物料管理_编辑` 仍写入 `货位流水号`。 +- `仓储管理_物料库位_编辑数据` 仍写入物料库位。 + +这说明 `sql/移除物料标准库位维护.sql` 尚未执行到目标数据库。 + +结论: + +部分通过。数据库对象存在,但后端脚本尚未发布。上线前必须执行 SQL 脚本。 + +### 3.6 库位基础数据与库存库位样本核对 + +测试目的: + +确认全库位查询、已有库存库位查询存在可用样本数据。 + +执行命令: + +```powershell +sqlcmd -S 192.168.1.27 -d ERPTOOL_JY_20250826Back -U sa -P ****** -C -Q "SET NOCOUNT ON; SELECT TOP 10 货位流水号,货位名称 FROM 库存管理_货位主文件 ORDER BY 货位流水号; SELECT TOP 10 物料名称,图号或型号,货位名称,库存,货位流水号 FROM 外购件库存_视图 WHERE ISNULL(库存,0)>0 ORDER BY 物料名称;" +``` + +测试结果摘要: + +全库位样本: + +```text +货位流水号 货位名称 +1 A1 +2 A1-1 +3 A1-2 +4 A1-3 +5 A1-4 +6 A1-5 +7 A1-6 +8 A1-7 +9 A1-8 +10 A1-9 +``` + +已有库存库位样本: + +```text +物料名称 图号或型号 货位名称 库存 货位流水号 +壳体I模具 XT50-2-07.01MJ 模具库 1.0 2588 +盔甲护罩(左) WRS5085L 07-12-03 1.0 3789 +垃圾袋 垃圾袋 A000 1.0 2514 +内六角圆柱头螺钉 M10x45 GB/T70.1-2008 A000 1184.0 2514 +``` + +结果说明: + +- 全库位基础数据存在。 +- 真实库存库位样本存在。 +- 可用于后续页面业务回归测试。 + +结论: + +通过。 + +### 3.7 前端生产构建测试 + +测试目的: + +确认本次前端修改没有引入 Vue/JavaScript 编译错误。 + +执行命令: + +```powershell +npm run build +``` + +测试结果摘要: + +```text +Hash: bfc0aa9b97bada6643bc +Version: webpack 4.16.5 +Time: 64306ms +Built at: 2026/06/29 14:57:00 +Build complete. +``` + +构建告警摘要: + +- asset size limit 超限。 +- entrypoint size limit 超限。 +- Browserslist/caniuse-lite 过期提示。 +- npm 日志无法写入用户 npm-cache 日志目录。 +- shelljs 循环依赖属性访问告警。 + +异常说明: + +构建已输出 `Build complete`,产物已生成;但命令进程在构建完成后未及时退出,被工具在 180 秒时截断,退出码为 `124`。 + +判断: + +- 编译结果:通过。 +- 命令退出:异常,疑似项目旧构建脚本或环境中残留进程导致。 +- 告警均为项目既有构建告警或环境日志权限告警,本次未发现由修改代码造成的编译错误。 + +结论: + +条件通过。 + +## 四、功能测试结论 + +| 测试项 | 结果 | 说明 | +| --- | --- | --- | +| 物料新增/编辑库位 UI 移除 | 通过 | 静态检查无残留 | +| 物料库位维护编辑能力移除 | 通过 | 静态检查无残留 | +| 入库库存库位优先逻辑 | 通过 | 关键代码路径存在 | +| 入库无库存 fallback 全库位 | 通过 | 关键代码路径存在 | +| SQL 脚本静态检查 | 通过 | 脚本未写标准库位 | +| 数据库对象参数核对 | 通过 | 所需过程和参数存在 | +| 目标数据库后端脚本发布状态 | 未完成 | 当前库仍为旧过程 | +| 前端生产构建 | 条件通过 | 已 Build complete,但进程超时退出 | + +## 五、待办与风险 + +### 5.1 必须执行的上线前动作 + +1. 在目标数据库执行: + +```text +sql/移除物料标准库位维护.sql +``` + +2. 执行后重新核对: + +```sql +SELECT o.name, + CASE WHEN m.definition LIKE N'%库存管理_物料与货位对照表%' THEN 1 ELSE 0 END AS TouchMaterialLocationTable, + CASE WHEN m.definition LIKE N'%货位流水号=@货位流水号%' OR m.definition LIKE N'%货位流水号 = @货位流水号%' THEN 1 ELSE 0 END AS WritesLocationSerial +FROM sys.objects o +JOIN sys.sql_modules m ON o.object_id = m.object_id +WHERE o.name IN (N'物料管理_增加', N'物料管理_增加新', N'物料管理_编辑'); +``` + +预期: + +- `TouchMaterialLocationTable = 0` +- `WritesLocationSerial = 0` + +### 5.2 需要人工页面回归的场景 + +由于本次未启动登录态浏览器访问业务系统,以下场景需要在测试环境人工回归: + +- 新增物料弹窗不显示库位。 +- 编辑物料弹窗不显示库位。 +- 新增物料后数据库不生成 0 库存库位记录。 +- 编辑物料不改变已有真实库存库位。 +- 物料库位维护页面不可编辑。 +- 采购入库已有库存物料时,下拉只显示已有库存库位。 +- 采购入库无库存物料时,下拉显示全库位。 +- 自制件入库已有库存物料时,下拉只显示已有库存库位。 +- 自制件入库无库存物料时,下拉显示全库位。 +- 未选择库位时仍禁止入库。 +- 选择库位后入库成功,入库记录显示正确库位。 + +### 5.3 风险项 + +- 目标数据库当前仍是旧过程,若不执行 SQL 脚本,新增/编辑物料仍可能写入标准库位或物料货位对照数据。 +- 旧历史数据中已有 0 库存物料货位记录,本次不清理;若某些视图未过滤库存大于 0,仍可能被查询显示。 +- `npm run build` 构建完成后进程未正常退出,建议后续单独排查构建脚本或环境中的挂起任务。 + +## 六、最终结论 + +本次代码级测试与构建测试总体通过: + +- 前端库位维护能力已按设计移除。 +- 入库库位选择逻辑已按设计实现。 +- SQL 脚本已准备完成,静态检查符合预期。 +- 生产构建已输出 `Build complete`。 + +当前不满足完整上线闭环的唯一关键项: + +- 目标数据库尚未执行 `sql/移除物料标准库位维护.sql`。 + +建议先在测试数据库执行 SQL 脚本,再按 5.2 的页面回归清单完成业务验证。 diff --git a/docs/物料库位设置/物料库位功能调整设计方案.md b/docs/物料库位设置/物料库位功能调整设计方案.md index 47b0de7d..2aa6fabd 100644 --- a/docs/物料库位设置/物料库位功能调整设计方案.md +++ b/docs/物料库位设置/物料库位功能调整设计方案.md @@ -12,11 +12,13 @@ 本次调整目标是: -1. 物料主档不再设置库位。 +1. 物料主档不再强制维护真实库存库位。 2. 物料标准维护组件不再编辑物料库位。 3. 入库时根据真实库存情况选择库位。 4. 有现有库存库位时优先显示已有库存库位;没有库存库位时显示全库位。 5. 盘点人员后续依据系统库存查询结果进行盘点时,系统库位应尽可能来源于仓库真实业务记录,减少基础资料预设库位造成的现场偏差。 +6. 库存盘点组件增加物料存货功能修改,增加物料是可以选择库位 +7. 库存查询组件主列表“库位”列显示该物料当前有库存且库存数最多的库位;点击该库位可查看该物料所有有库存的库位及对应库存数。 ## 二、现状核对 @@ -74,15 +76,16 @@ ## 三、设计原则 -1. 物料主档只维护物料基础属性,不再维护库存库位。 -2. 库位选择只发生在入库、调拨、盘点等库存业务动作中。 -3. 入库库位选择以真实库存记录优先。 +1. 物料主档可记录“存放库位/建议库位”,但维护入口不放在物料新建页面,且该库位不等同于真实库存库位。 +2. 真实库存库位只由入库、调拨、盘点等库存业务动作产生或调整。 +3. 入库库位选择以真实库存记录优先;没有真实库存库位时,可参考物料存放库位或全库位选择。 4. 保留旧接口参数兼容,降低前后端发布顺序风险。 5. 不删除历史库位数据,避免影响历史库存、出入库记录和查询报表。 6. 仓库库位数据应以仓库人员实际作业确认结果为准,避免由技术、基础资料维护环节提前指定库位。 7. 当前库存盘点期间,优先保障盘点人员能够通过系统库存数据定位真实库位;对历史不准确库位数据不做批量自动修正,防止误改真实库存,需要结合盘点结果逐步校正。 +8. 库存查询主列表以“库存数最多的库位”作为默认展示库位,降低一物多库位时主表信息分散和误判风险。 -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +
## 四、前端改造方案 @@ -95,47 +98,39 @@ 改造内容: -- 删除新增/编辑弹窗中的“库位”下拉控件。 +- 新增物料弹窗不显示库位或存放库位字段。 +- 编辑物料弹窗不显示库位或存放库位字段。 - 删除 `form.库位` 字段。 - 删除 `库位` 必填校验。 - 删除 `inventoryLocation` 数据源。 - 删除 `getInventoryLocation()` 方法及页面初始化调用。 -- 删除新增时默认 `form.库位 = 2514`。 -- 编辑物料时不再从行数据读取 `货位流水号` 回填到表单。 -- 新增/编辑提交时保留 `货位流水号 = null` 参数,用于兼容旧存储过程参数要求。 +- 删除新增时默认 `form.库位 = 2514`,避免未选择时自动落到固定库位。 +- 新增/编辑提交时传递 `货位流水号 = null`,不在物料建档流程中写入存放库位或真实库存库位。 说明: -前端不再提供物料库位维护入口。保留 `货位流水号 = null` 是为了在数据库脚本未执行或前后端不同步发布时,减少接口缺参风险。 +物料新建和编辑只维护物料基础属性,不维护库位。这样可以避免技术或基础资料人员在建档阶段提前指定库位,把库位维护职责交还给仓储相关组件。 -该调整可以避免非仓库人员在维护物料基础资料时预先指定库位,减少后续库存盘点时系统库位与实物库位不一致的问题。 +存放库位仍然允许维护,但入口应放在仓储侧的独立组件或现有物料库位组件中,业务含义是“建议存放位置”,不是库存现存量位置。 -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +
-### 4.2 物料库位维护页面 +### 4.2 新增存放库位功能 -涉及文件: +承载方案: -- `src/views/WarehouseManagement/MaterialLocation/index.vue` +- 方案 :修改 `src/views/WarehouseManagement/InventoryCheck/index.vue` 库存盘点页面。 改造内容: -- 删除行内库位下拉编辑。 -- 删除编辑、确定、取消按钮。 -- 删除双击行切换编辑状态。 -- 删除 `storageLocation` 数据源。 -- 删除 `getLocateName()`。 -- 删除 `confirmEdit()`,不再调用 `仓储管理_物料库位_编辑数据`。 -- 删除页面中不可达的“增加库位”弹窗和新增库位方法。 -- 页面保留查询能力,用于查看历史物料库位数据。 +- 增加物料存货按钮功能修改,在添加时可以选择库位并且库存数可以为0 +- 操作列添加删除按钮,将原先编辑按钮库存数是0的库位删除功能调整到删除按钮上,库存数为0时不删除库位 说明: -该页面调整为只读查询页。后续如果确认不再需要查看历史标准库位,可在菜单侧隐藏该页面。 +用于仓库存放物料时原库位放不下时可以给该物料新建一个库位存放物料,当物料不打算放在该库位时确认库存为0便可删除物料与库位的关联,同时库位还打算存放该物料不会应为库存为0删除库位。 -只读保留的目的,是在盘点期间为仓库主管和盘点人员提供历史库位追溯依据,便于判断差异来源是历史标准库位错误、实际移库未更新,还是入库时选择库位不准确。该页面不再允许直接修改库位,避免绕过真实库存业务动作造成新的库位偏差。 - -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +
### 4.3 入库库位选择 @@ -154,6 +149,7 @@ - 下拉显示格式为 `货位名称(库存:数量)`。 - 设置 `locateSource = 'inventory'`。 - 如果不存在库存库位: + - 若物料主档存在存放库位,可优先把该库位排在下拉列表首位,并标记为建议库位。 - 当前行 `locateName` 使用全库位列表。 - 设置 `locateSource = 'all'`。 - 入库提交逻辑保持不变,继续校验并提交 `货位流水号组`。 @@ -162,10 +158,90 @@ - 仓库人员办理采购入库、自制件入库时,必须根据现场实际上架库位选择系统库位。 - 系统存在该物料真实库存库位时,优先引导仓库人员选择已有库存库位,便于同物料集中存放和后续盘点。 -- 系统不存在该物料真实库存库位时,允许从全库位中选择本次实际上架库位,形成后续库存查询和盘点依据。 +- 系统不存在该物料真实库存库位时,可以参考物料新建时维护的存放库位;仓库人员仍可从全库位中选择本次实际上架库位,形成后续库存查询和盘点依据。 - 盘点发现实物库位与系统库位不一致时,应通过盘点调整、移库或后续明确的库存业务流程修正,不再通过物料基础资料维护直接改库位。 -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +
+ +### 4.4 库存查询库位展示与明细查看 + +涉及文件: + +- `src/views/WarehouseManagement/InventoryQuery/index.vue` + +当前现状: + +- 主表已有“库位”列,当前展示 `scope.row.货位名称`。 +- 主表已有“库存”列,展示该行 `scope.row.库存`。 +- 主表已有 `@cell-click="handleEdit"`,当前只处理点击“物料编码”展开出入库记录。 +- 页面查询调用 `仓储管理_库存查询_查询`。 + +改造目标: + +- 库存查询主列表每个物料只展示一个主库位。 +- 主库位取该物料所有有库存库位中库存数最多的库位。 +- 用户点击主库位后,弹出或展开该物料所有有库存库位明细。 + +前端改造内容: + +- 将“库位”列展示改为可点击文本。 +- 库位列显示字段建议为 `最大库存库位名称`,如后端暂不改字段名,也可继续使用 `货位名称`,但后端需保证该字段已经是最大库存库位。 +- 点击库位列时调用 `handleLocationClick(row)`。 +- 新增库位明细弹窗或 `el-popover`: + - 表格列包含 `货位名称`、`货位存量`、`批次编号`、`供应商`、`最后入库日期` 等字段。 + - 明细只显示 `货位存量 > 0` 的库位。 + - 默认按 `货位存量 DESC` 排序。 +- 如果物料只有一个有库存库位,点击仍可显示明细,方便盘点人员查看库存数来源。 + +后端改造建议: + +- 新增或调整库存查询明细过程,例如: + - `仓储管理_库存查询_物料库位明细_查询` +- 入参: + - `物料流水号` +- 返回: + - `物料流水号` + - `物料编码` + - `物料名称` + - `图号或型号` + - `货位流水号` + - `货位名称` + - `货位存量` + - `批次编号` + - `供应商` +- 主查询 `仓储管理_库存查询_查询` 调整为: + - 按物料聚合库存。 + - 对每个物料取 `货位存量` 最大的库位作为主表 `货位名称`。 + - 若多个库位库存数相同,按 `货位流水号` 或 `货位名称` 稳定排序取第一条。 + +示例 SQL 思路: + +```sql +WITH LocationRank AS ( + SELECT + 物料流水号, + 货位流水号, + 货位名称, + 货位存量, + ROW_NUMBER() OVER ( + PARTITION BY 物料流水号 + ORDER BY ISNULL(货位存量, 0) DESC, 货位流水号 ASC + ) AS rn + FROM 库存管理_物料与货位对照表 + LEFT JOIN 库存管理_货位主文件 + ON 库存管理_物料与货位对照表.货位流水号 = 库存管理_货位主文件.货位流水号 + WHERE ISNULL(货位存量, 0) > 0 +) +SELECT * +FROM LocationRank +WHERE rn = 1; +``` + +业务说明: + +- 主表库位用于快速定位优先盘点库位。 +- 明细库位用于处理一物多库位、一物多批次的盘点场景。 +- 主表库存仍应为该物料总库存,不能只显示最大库位库存。 ## 五、后端改造方案 @@ -182,24 +258,26 @@ 调整内容: - 保留 `@货位流水号` 参数,兼容旧调用。 -- 新增物料时不再写入 `库存管理_物料主文件_基本.货位流水号`。 +- 新增物料时允许写入 `库存管理_物料主文件_基本.货位流水号`,作为物料“存放库位/建议库位”。 - 新增物料时不再向 `库存管理_物料与货位对照表` 插入 `货位存量 = 0` 的初始记录。 -- 编辑物料时不再更新 `库存管理_物料主文件_基本.货位流水号`。 +- 编辑物料时默认不更新 `库存管理_物料主文件_基本.货位流水号`,除非后续明确增加“修改存放库位”的独立权限入口。 - 编辑物料时不再更新 `库存管理_物料与货位对照表.货位流水号`。 +- 库存查询主过程需按物料聚合真实库存,并返回库存数最多的库位作为主表展示库位。 +- 新增库存查询库位明细过程,用于点击主表库位时查看该物料所有有库存库位。 不调整内容: - 入库过程仍继续接收 `货位流水号组`。 -- 历史物料主档中的 `货位流水号` 暂不清理。 +- 历史物料主档中的 `货位流水号` 暂不清理,后续作为存放库位参考。 - 历史 `库存管理_物料与货位对照表` 中的 0 库存记录暂不清理。 后端调整边界: - 本次不批量重算历史库存库位,避免在盘点期间引入新的数据扰动。 -- 对已产生实际库存的物料库位关系,以库存业务单据和库存现存量记录为准。 +- 对已产生实际库存的物料库位关系,以库存业务单据和库存现存量记录为准;物料主档存放库位只作为建议或参考。 - 后续若仓库主管确认需要清理历史 `货位存量 = 0` 的无效库位记录,应另行制定数据清理脚本,并在盘点结束或盘点数据确认后执行。 -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +
## 六、入库库位选择流程 @@ -208,28 +286,44 @@ flowchart TD A["用户点击入库行的库位按钮"] --> B["按物料名称和图号查询库存盘点"] B --> C{"是否存在库存大于 0 的库位"} C -->|是| D["显示已有库存库位"] - C -->|否| E["显示全库位"] + C -->|否| E{"物料是否维护存放库位"} + E -->|是| E1["全库位列表中优先展示存放库位"] + E -->|否| E2["显示全库位"] D --> F["用户选择库位"] - E --> F + E1 --> F + E2 --> F F --> G["写回行数据: 货位流水号、货位名称"] G --> H["入库提交"] H --> I["提交货位流水号组"] ``` -## 七、影响范围 +## 七、库存查询库位展示流程 -### 7.1 受影响页面 +```mermaid +flowchart TD + A["库存查询加载主列表"] --> B["按物料汇总所有有库存库位"] + B --> C["按货位存量倒序排序"] + C --> D["取库存数最多的库位作为主表库位"] + D --> E["用户点击主表库位"] + E --> F["查询该物料所有货位存量大于 0 的库位"] + F --> G["弹窗展示库位、库存数、批次等明细"] +``` + +## 八、影响范围 + +### 8.1 受影响页面 - 技术中心物料维护 - 技术中心物料查询 - 仓储管理物料库位 - 仓储管理采购入库 - 仓储管理自制件入库 +- 仓储管理库存查询 - 库存盘点人员使用的库存查询和盘点核对结果会间接受益于本次调整,后续新增库存的系统库位将更贴近现场真实库位。 -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +
-### 7.2 受影响数据库对象 +### 8.2 受影响数据库对象 - `库存管理_物料主文件_基本` - `库存管理_物料与货位对照表` @@ -237,40 +331,45 @@ flowchart TD - `物料管理_增加` - `物料管理_增加新` - `物料管理_编辑` +- `仓储管理_库存查询_查询` +- 新增 `仓储管理_库存查询_物料库位明细_查询` -### 7.3 不受影响业务 +### 8.3 不受影响业务 -- 已有库存查询。 - 已有入库记录查询。 - 已有出库、领料、调拨中基于真实库存记录的库位逻辑。 - 库位基础资料维护页面 `LocationManagement`。 - 当前历史库存数量不因本次调整自动变化。 - 当前盘点差异数据不因本次调整自动生成或自动消除。 -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +
-## 八、发布步骤 +## 九、发布步骤 1. 发布前端代码。 2. 执行 `sql/移除物料标准库位维护.sql`。 3. 清浏览器缓存后进入系统验证。 -4. 验证物料新增、编辑不再出现库位字段。 +4. 验证物料新增可选择存放库位,编辑物料不修改真实库存库位。 5. 验证物料库位维护页不可编辑。 6. 验证采购入库和自制件入库的库位选择逻辑。 -7. 由仓库主管或指定仓库人员抽取正在盘点的物料进行核对,确认系统库存库位、入库选择库位和现场实际库位的对应关系。 -8. 对盘点期间发现的历史库位不一致数据,记录物料名称、图号、系统库位、实际库位和差异原因,作为后续数据清理或库存调整依据。 +7. 验证库存查询主表库位显示库存数最多的库位。 +8. 验证点击库存查询主表库位可查看该物料所有有库存库位。 +9. 由仓库主管或指定仓库人员抽取正在盘点的物料进行核对,确认系统库存库位、入库选择库位和现场实际库位的对应关系。 +10. 对盘点期间发现的历史库位不一致数据,记录物料名称、图号、系统库位、实际库位和差异原因,作为后续数据清理或库存调整依据。 -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +
推荐前后端同时发布。若不能同时发布,先发布后端脚本更稳妥。 -## 九、验证清单 +## 十、验证清单 ### 9.1 物料新增 -- 新增弹窗不显示库位。 +- 新增弹窗显示“存放库位”。 +- 存放库位非必填。 - 新增物料可正常保存。 -- 新增后 `库存管理_物料主文件_基本.货位流水号` 不写入新默认库位。 +- 新增时选择存放库位后,`库存管理_物料主文件_基本.货位流水号` 写入该建议库位。 +- 新增时不选择存放库位后,`库存管理_物料主文件_基本.货位流水号` 为空。 - 新增后不生成 `货位存量 = 0` 的物料货位对照记录。 ### 9.2 物料编辑 @@ -278,6 +377,7 @@ flowchart TD - 编辑弹窗不显示库位。 - 修改名称、图号、单位、材料、类型、物料库等字段可正常保存。 - 编辑时不改变物料已有真实库存库位。 +- 编辑时不覆盖物料主档存放库位。 ### 9.3 物料库位查询 @@ -302,21 +402,32 @@ flowchart TD - 对无真实库存的物料,不应因为物料新增自动生成 `货位存量 = 0` 的库位记录干扰盘点查询。 - 对现场已发现系统库位与实际库位不一致的物料,应形成差异记录,不通过物料主档编辑直接修正。 -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +### 9.6 库存查询库位展示 -## 十、风险与回退 +- 一物一库位时,主表库位显示该库位。 +- 一物多库位时,主表库位显示 `货位存量` 最大的库位。 +- 多个库位库存数相同,主表库位按稳定排序规则显示固定结果。 +- 主表“库存”列显示物料总库存,不显示单个库位库存。 +- 点击主表库位,弹出该物料所有 `货位存量 > 0` 的库位明细。 +- 库位明细按库存数倒序显示。 +- 库位明细中不显示 0 库存库位。 -### 10.1 风险 +
-- 若后端脚本未执行,前端传 `货位流水号 = null` 时,旧过程仍可能向物料主档或对照表写入空库位记录。 +## 十一、风险与回退 + +### 11.1 风险 + +- 若后端脚本未执行,物料新增时仍可能向物料货位对照表写入 `货位存量 = 0` 的记录。 - 历史 0 库存物料货位记录仍存在,若库存盘点视图没有过滤库存数量,可能仍被查询出来。 -- 部分报表如依赖物料主档默认库位,展示结果会从“标准库位”转为“历史库位”或空值。 +- 部分报表如依赖物料主档默认库位,需要明确该字段现在是“存放库位/建议库位”,不代表真实库存库位。 - 当前盘点期间已经暴露的历史库位不匹配问题,不会因本次功能调整自动修复,需要仓库结合盘点结果进行后续校正。 - 若仓库人员入库时未按实际上架位置选择库位,仍可能继续产生新的系统库位与实际库位不一致问题,因此需要同步明确仓库操作要求。 +- 库存查询主表改为显示最大库存库位后,用户可能误以为物料只在该库位,需要通过点击明细和文案提示说明“一物可能多库位”。 -备注:修改人:Ld 修改时间:2026-06-29 13:11:25 +
-### 10.2 回退方式 +### 11.2 回退方式 - 前端回退相关 Vue 文件。 - 数据库可用脚本备份中的原存储过程定义恢复。 diff --git a/docs/物料编码搜索功能/核心物料搜索栏添加物料编码查询测试报告.md b/docs/物料编码搜索功能/核心物料搜索栏添加物料编码查询测试报告.md new file mode 100644 index 00000000..0a92e746 --- /dev/null +++ b/docs/物料编码搜索功能/核心物料搜索栏添加物料编码查询测试报告.md @@ -0,0 +1,158 @@ +# 核心物料搜索栏添加物料编码查询测试报告 + +备注:修改人:Ld 修改时间:2026-06-29 15:06:32 + +## 1. 测试背景 + +本次测试对应罗伟提出的“核心物料搜索栏页面添加物料编码搜索功能”需求。现场库存盘点过程中,存在部分物料在新建时因物料名称、图号重复命名导致盘点人员难以准确确认物料的问题。后续现场计划在物料标签中使用唯一物料编码进行识别,因此系统核心物料搜索栏需要支持按物料编码进行查询和筛选,便于盘点、库存查询、物料库位查询、入库记录、出入库记录等业务快速匹配唯一物料。 + +测试目标是确认前端核心页面已增加物料编码搜索条件,后端核心查询存储过程已支持物料编码参数,且通过真实数据库数据验证物料编码能够正确筛选目标物料。 + +备注:修改人:Ld 修改时间:2026-06-29 15:06:32 + +## 2. 测试环境 + +| 项目 | 内容 | +| --- | --- | +| 项目路径 | D:\景耀\JY1.0 | +| 前端框架 | Vue 2.5.17、Element UI 2.13.0 | +| 模板编译工具 | vue-template-compiler 2.5.17 | +| 数据库服务器 | 192.168.1.27 | +| 数据库名称 | ERPTOOL_JY_20250826Back | +| 数据库账号 | sa | +| 数据库密码 | 已脱敏,不在测试文档中明文记录 | +| 测试时间 | 2026-06-29 15:03 至 2026-06-29 15:06 | +| 测试人员 | GPT/Codex | + +备注:修改人:Ld 修改时间:2026-06-29 15:06:32 + +## 3. 测试范围 + +### 3.1 前端页面范围 + +| 序号 | 页面 | 文件 | +| --- | --- | --- | +| 1 | 技术中心-物料查询 | src/views/TechnologyCenter/MaterialQuery/index.vue | +| 2 | 技术中心-物料维护 | src/views/TechnologyCenter/MaterialMaintain/index.vue | +| 3 | 仓储管理-库存查询 | src/views/WarehouseManagement/InventoryQuery/index.vue | +| 4 | 仓储管理-物料库位 | src/views/WarehouseManagement/MaterialLocation/index.vue | +| 5 | 仓储管理-库存盘点 | src/views/WarehouseManagement/InventoryCheck/index.vue | +| 6 | 仓储管理-入库记录 | src/views/WarehouseManagement/WarehousingRecord/WarehousingRecord.vue | +| 7 | 仓储管理-物料记录 | src/views/WarehouseManagement/MaterialRecord/index.vue | +| 8 | 仓储管理-盘点记录 | src/views/WarehouseManagement/InventoryRecord/index.vue | +| 9 | 仓储管理-入库退货记录 | src/views/WarehouseManagement/ReturnRecord/index.vue | + +### 3.2 数据库过程范围 + +| 序号 | 存储过程 | +| --- | --- | +| 1 | 物料管理_查询数据_分页 | +| 2 | 仓储管理_库存查询_查询 | +| 3 | 报表_仓储管理_通用库存_查询 | +| 4 | 仓储管理_库存盘点_查询 | +| 5 | 仓储管理_物料库位_查询数据 | +| 6 | 仓储管理_入库记录_查询 | +| 7 | 仓储管理_入库记录_导出表格_查询 | +| 8 | 仓储管理_物料记录_查询新 | +| 9 | 仓储管理_物料记录_查询 | +| 10 | 报表_仓储管理_物料记录_查询 | +| 11 | 仓储管理_盘点记录_查询 | +| 12 | 报表_仓储管理_盘点记录_查询 | +| 13 | 仓储管理_入库记录退货_条件查询 | + +### 3.3 脚本范围 + +| 类型 | 文件 | +| --- | --- | +| SQL调整脚本 | sql/核心物料搜索栏_物料编码查询_存储过程调整.sql | +| 设计方案文档 | docs/核心物料搜索栏添加物料编码查询设计方案.md | + +备注:修改人:Ld 修改时间:2026-06-29 15:06:32 + +## 4. 测试方法 + +1. 使用 vue-template-compiler 对核心页面 Vue 单文件组件模板进行编译检查,确认新增物料编码搜索栏不会导致模板语法错误。 +2. 使用静态检索检查核心页面是否存在物料编码搜索栏、物料编码字段绑定、物料编码请求参数和后端参数名。 +3. 使用静态检索确认核心页面搜索栏中不再残留容易造成现场误解的“物料编号”展示文案。 +4. 连接 SQL Server 测试库,检查核心存储过程是否均已具备 `@物料编码_check` 和 `@物料编码` 参数。 +5. 使用不存在的物料编码 `__CODEX_NOT_EXISTS__` 执行核心查询过程,验证过程能够正常执行且筛选无匹配数据时不报错。 +6. 从物料主文件中选取真实物料编码 `03.101.001.0011`,执行物料主数据、库存查询、物料库位、库存盘点等关键链路查询,验证可按物料编码返回目标物料。 + +备注:修改人:Ld 修改时间:2026-06-29 15:06:32 + +## 5. 测试用例与结果 + +| 用例编号 | 测试项 | 测试步骤 | 期望结果 | 实际结果 | 结论 | +| --- | --- | --- | --- | --- | --- | +| TC-001 | 前端模板编译 | 对 8 个已修改核心页面执行 Vue 模板编译 | 模板编译通过,无语法错误 | 8 个页面均返回 template ok | 通过 | +| TC-002 | 前端物料编码搜索栏覆盖 | 检索 `placeholder="物料编码"`、`label="物料编码"`、`物料编码_check`、`materialCodeValue`、`MaterialCode`、`materialCode` | 核心页面存在物料编码输入框、导出条件和请求参数 | 9 个核心页面均检索到预期字段或参数 | 通过 | +| TC-003 | 前端旧文案清理 | 检索核心页面中的 `placeholder="物料编号"` 和 `label="物料编号"` | 核心搜索栏不再展示“物料编号”旧文案 | 未检索到旧展示文案 | 通过 | +| TC-004 | 数据库存储过程参数覆盖 | 查询 13 个核心存储过程的参数 | 每个过程均包含 `@物料编码_check` 和 `@物料编码` | 13 个过程均返回 CodeParamCount=2 | 通过 | +| TC-005 | 不存在物料编码查询 | 使用 `__CODEX_NOT_EXISTS__` 执行物料记录、盘点记录、报表等过程 | 过程正常执行,无 SQL 错误,允许无数据返回 | 所有执行过程退出码为 0,导出类过程返回导出元数据 | 通过 | +| TC-006 | 物料主数据按编码查询 | 使用真实编码 `03.101.001.0011` 执行 `物料管理_查询数据_分页` | 返回该编码对应物料 | 返回物料编码 `03.101.001.0011`,物料名称为 `304不锈钢内外牙螺母转换变径牙套` | 通过 | +| TC-007 | 库存查询按编码查询 | 使用真实编码执行 `仓储管理_库存查询_查询` | 库存查询结果限定目标物料 | 返回物料编码 `03.101.001.0011` 及对应名称、规格信息 | 通过 | +| TC-008 | 物料库位按编码查询 | 使用真实编码执行 `仓储管理_物料库位_查询数据` | 物料库位结果限定目标物料 | 返回物料编码 `03.101.001.0011`、物料流水号 `24371`、物料分类编号 `2581` | 通过 | +| TC-009 | 库存盘点按编码查询 | 使用真实编码执行 `仓储管理_库存盘点_查询` | 盘点列表结果限定目标物料 | 返回物料编码 `03.101.001.0011` 及对应盘点字段 | 通过 | +| TC-010 | 导出过程参数兼容 | 检查导出类存储过程并执行无匹配编码场景 | 导出过程接受物料编码参数且不报错 | `报表_仓储管理_物料记录_查询`、`报表_仓储管理_盘点记录_查询` 均正常返回导出元数据 | 通过 | + +备注:修改人:Ld 修改时间:2026-06-29 15:06:32 + +## 6. 关键测试输出摘要 + +### 6.1 前端模板编译结果 + +```text +src/views/TechnologyCenter/MaterialMaintain/index.vue template ok +src/views/WarehouseManagement/MaterialRecord/index.vue template ok +src/views/WarehouseManagement/InventoryRecord/index.vue template ok +src/views/WarehouseManagement/ReturnRecord/index.vue template ok +src/views/WarehouseManagement/MaterialLocation/index.vue template ok +src/views/WarehouseManagement/InventoryCheck/index.vue template ok +src/views/WarehouseManagement/InventoryQuery/index.vue template ok +src/views/WarehouseManagement/WarehousingRecord/WarehousingRecord.vue template ok +``` + +### 6.2 数据库存储过程参数检查结果 + +```text +报表_仓储管理_盘点记录_查询 CodeParamCount=2 +报表_仓储管理_通用库存_查询 CodeParamCount=2 +报表_仓储管理_物料记录_查询 CodeParamCount=2 +仓储管理_库存查询_查询 CodeParamCount=2 +仓储管理_库存盘点_查询 CodeParamCount=2 +仓储管理_盘点记录_查询 CodeParamCount=2 +仓储管理_入库记录_查询 CodeParamCount=2 +仓储管理_入库记录_导出表格_查询 CodeParamCount=2 +仓储管理_入库记录退货_条件查询 CodeParamCount=2 +仓储管理_物料记录_查询 CodeParamCount=2 +仓储管理_物料记录_查询新 CodeParamCount=2 +仓储管理_物料库位_查询数据 CodeParamCount=2 +物料管理_查询数据_分页 CodeParamCount=2 +``` + +### 6.3 真实物料编码验证结果 + +| 验证编码 | 物料名称 | 规格 | 关键结果 | +| --- | --- | --- | --- | +| 03.101.001.0011 | 304不锈钢内外牙螺母转换变径牙套 | M8×M12×L20 | 物料主数据、库存查询、物料库位、库存盘点均可按编码返回目标物料 | + +备注:修改人:Ld 修改时间:2026-06-29 15:06:32 + +## 7. 风险与限制 + +1. 本次未执行浏览器登录后的端到端点击测试,原因是当前测试环境未启动已认证的前端业务系统;已通过 Vue 模板编译、静态字段覆盖和数据库真实过程调用验证核心链路。 +2. 本次未执行完整 `npm run build`,避免对当前工作区已有构建产物和无关脏文件产生额外影响;如后续上线前需要,可单独执行完整构建验证。 +3. SQL 正向测试依赖当前测试库真实数据,若后续物料编码 `03.101.001.0011` 被删除、停用或调整,复测时需要重新选取存在的物料编码。 +4. `仓储管理_库存查询_查询` 执行时会输出动态 SQL 文本,该输出为过程现有行为,不属于本次物料编码查询改造错误。 + +备注:修改人:Ld 修改时间:2026-06-29 15:06:32 + +## 8. 测试结论 + +本次测试结论为通过。 + +核心物料搜索栏已覆盖物料编码查询条件,相关前端页面模板编译通过,核心页面未残留容易混淆的“物料编号”搜索栏展示文案。数据库侧 13 个核心查询及导出存储过程均已包含物料编码筛选参数,使用不存在编码和真实编码分别验证后,过程执行正常,真实物料编码能够正确匹配物料主数据、库存查询、物料库位和库存盘点结果。 + +该功能满足现场库存盘点通过唯一物料编码快速确认物料的需求,可进入后续人工业务验收和上线前回归验证阶段。 + +备注:修改人:Ld 修改时间:2026-06-29 15:06:32 diff --git a/docs/核心物料搜索栏添加物料编码查询设计方案.md b/docs/物料编码搜索功能/核心物料搜索栏添加物料编码查询设计方案.md similarity index 100% rename from docs/核心物料搜索栏添加物料编码查询设计方案.md rename to docs/物料编码搜索功能/核心物料搜索栏添加物料编码查询设计方案.md diff --git a/docs/物料编号搜索功能设计说明.md b/docs/物料编码搜索功能/物料编号搜索功能设计说明.md similarity index 100% rename from docs/物料编号搜索功能设计说明.md rename to docs/物料编码搜索功能/物料编号搜索功能设计说明.md diff --git a/docs/零件改制/03-推进台账.md b/docs/零件改制/03-推进台账.md index c72d4383..67e94815 100644 --- a/docs/零件改制/03-推进台账.md +++ b/docs/零件改制/03-推进台账.md @@ -19,11 +19,15 @@ | 15 | 2026-06-27 | 执行不污染数据的测试并生成测试报告 | `零件改制功能测试报告.md` | eslint 通过;显示不一致数为 0;重复关联数为 0 | 补历史数据或做真实流程验收 | | 16 | 2026-06-29 | 修复生产任务查询动态 SQL 别名绑定问题 | `精工车间_生成任务_查询数据` | 将动态条件统一改为 `P.字段名` | 执行数据库过程更新并页面验证 | | 17 | 2026-06-29 | 拆分标准化推进文档 | `docs/零件改制/README.md`、`01-06` 文档 | 文档结构完成 | 后续按任务矩阵继续推进 | +| 18 | 2026-07-01 | 按推荐方案落地改制物料替换显示 | `技术中心_改制订单_发起改制`、`车间生产管理_零件工艺计划_视图`、`PartModificationOrder/index.vue` | 数据库结构验证通过,前端 eslint 通过 | 使用已维护新物料的测试订单做真实发起和入库验证 | +| 19 | 2026-07-01 | 修复发起改制后零件列表未按改制目标替换显示 | `技术中心_改制订单_零件_查询`、`技术中心_改制订单_发起改制`、`src/views/TechnologyCenter/PartModificationOrder/index.vue`、`sql/零件改制_发起改制_精确基本件.sql` | SQL 抽样验证:组件 4283 已显示 `XT40-205MF-01.02-G`,组件 2652 不再被串件覆盖;前端 eslint 通过 | 页面刷新后由接口回显最新改制目标,继续做真实发起与生产入库闭环验收 | ## 当前下一步 -1. 将 `精工车间_生成任务_查询数据` 最新完整 SQL 应用到数据库。 -2. 使用图号 `XT40-07.01` 再次执行查询,确认不再出现 4104 错误。 -3. 使用一条业务允许的测试订单发起真实改制。 -4. 验证生产任务查询、车间派工、MES 待加工显示。 -5. 补齐 3 条历史未回写 `工艺计划流水号` 的改制记录,或确认无需处理。 +1. 使用页面真实发起一条带 `原基本件流水号` 的改制订单。 +2. 验证改制发起页面刷新后只替换被点击的零件行。 +3. 验证生产任务查询、车间派工、MES 待加工显示。 +4. 验证自制件入库是否使用改制物料流水号。 +5. 补齐历史改制记录的 `改制物料流水号` 或确认无需处理。 + +修改人:Ld 修改时间:2026-07-01 14:46:30; diff --git a/docs/零件改制/04-任务矩阵.md b/docs/零件改制/04-任务矩阵.md index 555a5e4d..61b86d87 100644 --- a/docs/零件改制/04-任务矩阵.md +++ b/docs/零件改制/04-任务矩阵.md @@ -22,6 +22,8 @@ | GZ-018 | 改制记录查询页面 | 待开发 | 可按改制订单号、原订单、零件图号查询记录 | 后续新增 | | GZ-019 | 历史记录回写处理 | 待确认 | 未回写工艺计划流水号的历史记录明确处理方式 | 当前有 3 条未回写 | | GZ-020 | 完整业务流验收 | 待验收 | 使用测试订单完成发起、生产任务、派工、MES、入库验证 | 需业务允许测试数据 | +| GZ-021 | 改制任务入库链路验证 | 部分通过 | 完成生产后能进入自制件入库查询,且库存入到正确改制物料 | 当前仅验证可进入入库查询,库存物料流水号仍有风险 | +| GZ-022 | 改制物料流水号支持 | 已完成 | 改制记录保存目标物料流水号,入库使用改制目标物料 | 已加字段、改发起过程、改生产任务视图;历史数据未匹配到新物料 | ## 状态说明 @@ -41,4 +43,5 @@ 2. `GZ-020`:选择测试订单跑完整流程。 3. `GZ-016`、`GZ-017`:验证 MES 和车间派工显示。 4. `GZ-019`:确认历史未回写记录是否需要补数据。 -5. `GZ-018`:开发改制记录查询页面。 +5. 处理历史改制记录未维护改制物料流水号的问题。 +6. `GZ-018`:开发改制记录查询页面。 diff --git a/docs/零件改制/05-验收证据.md b/docs/零件改制/05-验收证据.md index c1ba914b..87ed7948 100644 --- a/docs/零件改制/05-验收证据.md +++ b/docs/零件改制/05-验收证据.md @@ -147,3 +147,170 @@ AND P.操作日期 <= @结束时间 | MES 待加工页面截图 | 待补充 | 需现场终端或模拟终端截图 | | 真实发起改制 job_id/report_id | 暂无 | 当前未通过自动化任务创建真实业务数据 | | 完整流程测试报告 | 待补充 | 需业务允许测试数据后生成 | + +## 8. 入库链路测试证据 + +测试报告: + +```text +docs/零件改制/零件改制入库链路测试报告.md +``` + +测试方式: + +- 使用事务临时将一条改制任务完成数量设置为批次数量。 +- 调用 `仓储管理_自制件入库_查询`。 +- 查询结束后立即 `ROLLBACK TRAN`,未保留业务数据改动。 + +测试结果: + +| 工艺计划流水号 | 订单号 | 零件名称 | 零件图号 | 物料流水号 | 批次数量 | 完成数量 | 入库数量 | 本次入库 | 类型 | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 6591 | BHGZ-202607010011 | 300封油板 | URS3042Z-07-01 | 741 | 1 | 1 | 0 | 1 | 自制件 | + +结论: + +- 改制任务完成生产后可以进入现有自制件入库查询。 +- 但当前库存入库仍使用原基本件物料流水号,存在入到原物料而非改制目标物料的风险。 + +后续验收要求: + +- 增加并维护 `改制物料流水号` 后,再验证库存是否入到正确改制物料。 + +## 9. 改制物料流水号修改证据 + +### 9.1 已完成修改 + +新增字段: + +```sql +ALTER TABLE dbo.技术中心_改制订单记录 +ADD 改制物料流水号 int NULL; +``` + +已修改过程: + +```text +dbo.技术中心_改制订单_发起改制 +``` + +发起改制时新增逻辑: + +```sql +SELECT TOP 1 + @改制物料流水号 = 物料流水号 +FROM dbo.库存管理_物料主文件_基本 +WHERE LTRIM(RTRIM(名称)) = LTRIM(RTRIM(@改制零件名称)) + AND LTRIM(RTRIM(代号)) = LTRIM(RTRIM(@改制零件图号)) + AND ISNULL(是否禁用, 0) = 0 +ORDER BY 物料流水号 DESC; + +IF @改制物料流水号 IS NULL +BEGIN + SELECT '0' AS result, '未找到改制零件对应的新物料,请先维护物料信息' AS msg; + RETURN; +END; +``` + +已修改视图: + +```text +dbo.车间生产管理_零件工艺计划_视图 +``` + +视图已关联: + +```sql +LEFT OUTER JOIN dbo.库存管理_物料主文件_基本 AS 改制物料 + ON dbo.技术中心_改制订单记录.改制物料流水号 = 改制物料.物料流水号 +``` + +并让以下字段优先使用改制物料: + +```text +零件名称 +零件图号 +物料流水号 +物料编码 +代号 +货位流水号 +单位 +``` + +### 9.2 结构验证 + +执行结果: + +| 检查项 | 结果 | +| --- | --- | +| 改制物料字段存在 | 1 | +| 发起过程已包含改制物料 | 1 | +| 生产任务视图已关联改制物料 | 1 | +| 发起过程会写入改制物料 | 1 | + +### 9.2.1 前端验证 + +修改文件: + +```text +src/views/TechnologyCenter/PartModificationOrder/index.vue +``` + +调整内容: + +- 发起改制弹窗打开后,改制零件名称和改制零件图号不再默认填原零件信息。 +- 提交前要求填写已维护的新物料名称和图号。 +- 保留原零件图号和改制零件图号不能相同的校验。 + +执行命令: + +```bash +npx eslint --ext .vue D:\景耀\JY1.0\src\views\TechnologyCenter\PartModificationOrder\index.vue +``` + +结果: + +```text +通过 +``` + +### 9.3 历史数据验证 + +执行结果: + +| 未删除改制记录数 | 未维护改制物料数 | 已维护改制物料数 | +| --- | --- | --- | +| 11 | 11 | 0 | + +结论: + +- 当前历史改制记录没有回填到 `改制物料流水号`。 +- 原因是现有物料主文件中没有与历史改制记录的“改制零件名称 + 改制零件图号”完全匹配的可用物料。 +- 新流程已经阻止继续产生这类数据:后续发起改制时,如果没有先维护物料信息,会返回失败提示。 + +## 10. 改制发起页面零件列表替换显示验证 + +执行命令: + +```powershell +sqlcmd -S 192.168.1.27 -d ERPTOOL_JY_20250826Back -U sa -P ****** -b -W -s "|" -Q "EXEC dbo.技术中心_改制订单_零件_查询 @组件流水号=4283; EXEC dbo.技术中心_改制订单_零件_查询 @组件流水号=2652;" +sqlcmd -S 192.168.1.27 -d ERPTOOL_JY_20250826Back -U sa -P ****** -b -f 65001 -i "sql\零件改制_发起改制_精确基本件.sql" +sqlcmd -S 192.168.1.27 -d ERPTOOL_JY_20250826Back -U sa -P ****** -b -W -s "|" -Q "SELECT PARAMETER_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME=N'技术中心_改制订单_发起改制' ORDER BY ORDINAL_POSITION;" +npx eslint "src/views/TechnologyCenter/PartModificationOrder/index.vue" +``` + +验证结果: + +| 验证项 | 结果 | +| --- | --- | +| 组件 4283 改制行 | `205伺服电机挂板 / XT40-205MF-01.02-G`,`是否改制=1` | +| 组件 2652 同流水号历史行 | 保持 `打刀缸 / NPM35T63x13BL-TZ1179C`,`是否改制=0` | +| 发起过程参数 | 已包含 `@原基本件流水号 int` | +| 前端 lint | 通过 | + +结论: + +- `技术中心_改制订单_零件_查询` 已按订单、组件、基本件三条件关联改制记录,避免只按基本件流水号导致串件。 +- 发起弹窗保留 `原零件名称`、`原零件图号`,列表展示可按最新改制目标替换。 + +修改人:Ld 修改时间:2026-07-01 14:46:30; diff --git a/docs/零件改制/06-决策记录.md b/docs/零件改制/06-决策记录.md index ef816885..d3161ba9 100644 --- a/docs/零件改制/06-决策记录.md +++ b/docs/零件改制/06-决策记录.md @@ -79,3 +79,73 @@ FROM 车间生产管理_零件工艺计划_视图 AS P ## DR-012:为什么保留历史设计方案和测试报告 本次拆分出的 `01-06` 文档用于后续推进和任务管理,原设计方案、开发说明、测试报告保留作为上下文证据,避免历史决策丢失。 + +## DR-013:为什么发起改制前必须先维护新物料 + +入库流程最终按 `物料流水号` 写入库存。如果只修改显示用的零件名称和图号,而不切换物料流水号,库存会入到原物料,造成库存台账错误。 + +因此最终规则调整为: + +```text +发起改制前,必须先在物料主文件维护改制后的新物料。 +发起改制时,系统使用改制零件名称 + 改制零件图号查询新物料流水号。 +查不到新物料时,禁止发起改制。 +``` + +对应查询条件: + +```sql +库存管理_物料主文件_基本.名称 = @改制零件名称 +库存管理_物料主文件_基本.代号 = @改制零件图号 +是否禁用 = 0 +``` + +## DR-014:为什么视图中的物料字段也要优先使用改制物料 + +现有入库查询、生产任务、派工和 MES 多处依赖 `车间生产管理_零件工艺计划_视图`。如果只在改制记录里保存改制物料流水号,但视图仍返回原物料流水号,入库仍会写错库存。 + +因此视图中以下字段统一优先取改制物料: + +```text +零件名称 +零件图号 +物料流水号 +物料编码 +代号 +货位流水号 +单位 +``` + +这样后续 `仓储管理_自制件入库_查询` 和 `仓储管理_自制件入库_循环执行` 不需要大改,就能按新物料入库。 + +## DR-015:为什么发起弹窗不再默认填入原零件名称和图号 + +如果弹窗默认把原零件名称、原零件图号带入改制目标,用户容易直接提交,虽然有“图号不能相同”的校验,但体验上仍然容易误解为可以在原零件基础上简单修改。 + +最终决定: + +```text +原零件信息只读展示。 +改制零件名称和改制零件图号默认置空。 +用户必须填写已经在物料信息中维护好的新物料名称和图号。 +后端根据名称 + 图号查找改制物料流水号。 +``` + +这样可以强化业务规则:改制目标必须先存在于物料主文件,后续入库才能入到正确物料。 + +## DR-016:为什么零件列表替换显示不直接修改原 BOM + +发起改制后,技术中心页面需要让用户看到“这条零件已经改制到哪个目标”,但原 BOM 仍然是订单原始技术数据,直接修改原 BOM 会影响历史追溯和未改制流程。 + +最终决定: + +```text +不修改原 BOM。 +零件列表查询时按最新未删除改制记录覆盖显示零件名称和图号。 +接口额外返回原零件名称、原零件图号,弹窗继续用于原件校验。 +关联条件必须包含原订单流水号、原组件流水号、原基本件流水号,避免同流水号跨组件串件。 +``` + +这样既满足页面可见性,也保证改制记录、生产任务、入库物料各自有清晰依据。 + +修改人:Ld 修改时间:2026-07-01 14:46:30; diff --git a/docs/零件改制/零件改制入库链路测试报告.md b/docs/零件改制/零件改制入库链路测试报告.md new file mode 100644 index 00000000..512370f0 --- /dev/null +++ b/docs/零件改制/零件改制入库链路测试报告.md @@ -0,0 +1,299 @@ +# 零件改制入库链路测试报告 + +## 1. 测试目的 + +验证零件改制任务在完成生产后,是否能够进入现有“自制件入库”流程,并判断是否存在入库数据风险。 + +## 2. 测试方式 + +本次采用只读查询和事务内回滚模拟方式测试。 + +- 未保留任何业务数据改动。 +- 未真实新增库存。 +- 未真实执行入库提交。 +- 使用事务临时修改完成数量,调用现有自制件入库查询过程后立即回滚。 + +## 3. 涉及对象 + +### 3.1 前端页面 + +```text +src/views/WarehouseManagement/PurchasePartsStorage/index.vue +``` + +自制件入库页签使用接口: + +```text +仓储管理_自制件入库_查询 +仓储管理_自制件入库_循环执行 +物料入库_自制件入库_零件图号_查询数据 +``` + +### 3.2 数据库对象 + +```text +技术中心_改制订单记录 +车间生产管理_零件工艺计划_视图 +车间生产管理工艺_零件工艺计划 +仓储管理_自制件入库_查询 +仓储管理_自制件入库_循环执行 +库存管理_物料与货位对照表 +库存管理_外购件累计库存 +库存管理_自制件_入库记录 +``` + +## 4. 当前改制任务状态检查 + +执行 SQL: + +```sql +SELECT + COUNT(*) AS 改制任务数, + SUM(CASE WHEN ISNULL(V.完成数量,0) > ISNULL(V.入库数量,0) THEN 1 ELSE 0 END) AS 当前可入库数, + SUM(CASE WHEN ISNULL(V.完成数量,0) >= ISNULL(V.批次数量,0) AND ISNULL(V.批次数量,0) > 0 THEN 1 ELSE 0 END) AS 已完成生产数, + SUM(CASE WHEN V.工艺计划流水号 IS NULL THEN 1 ELSE 0 END) AS 未关联生产任务数 +FROM dbo.技术中心_改制订单记录 GZ +LEFT JOIN dbo.车间生产管理_零件工艺计划_视图 V + ON GZ.工艺计划流水号 = V.工艺计划流水号 +WHERE ISNULL(GZ.是否删除,0)=0; +``` + +结果: + +| 改制任务数 | 当前可入库数 | 已完成生产数 | 未关联生产任务数 | +| --- | --- | --- | --- | +| 11 | 0 | 0 | 3 | + +结论: + +- 当前没有已经完成生产并可入库的改制任务。 +- 有 3 条历史改制记录未关联到生产任务,原因是未回写 `工艺计划流水号`。 + +## 5. 入库查询模拟测试 + +### 5.1 测试 SQL + +以下 SQL 在事务中临时将一条改制任务的 `完成数量` 设置为 `批次数量`,调用现有自制件入库查询后立即回滚。 + +```sql +BEGIN TRAN; + +DECLARE @工艺计划流水号 int; +DECLARE @订单流水号 int; +DECLARE @批次数量 int; +DECLARE @图号 nvarchar(50); + +SELECT TOP 1 + @工艺计划流水号 = V.工艺计划流水号, + @订单流水号 = V.订单流水号, + @批次数量 = V.批次数量, + @图号 = V.零件图号 +FROM dbo.技术中心_改制订单记录 GZ +INNER JOIN dbo.车间生产管理_零件工艺计划_视图 V + ON GZ.工艺计划流水号 = V.工艺计划流水号 +WHERE ISNULL(GZ.是否删除,0)=0 + AND V.工艺计划流水号 IS NOT NULL +ORDER BY GZ.改制订单流水号 DESC; + +UPDATE dbo.车间生产管理工艺_零件工艺计划 +SET 完成数量 = @批次数量 +WHERE 工艺计划流水号 = @工艺计划流水号; + +EXEC dbo.仓储管理_自制件入库_查询 + @排序名称 = 0, + @排序方式 = 0, + @订单号_check = 1, + @订单号 = @订单流水号, + @零件图号_check = 1, + @零件图号 = @图号; + +ROLLBACK TRAN; +``` + +### 5.2 查询结果 + +| 工艺计划流水号 | 订单号 | 零件名称 | 零件图号 | 物料流水号 | 批次数量 | 完成数量 | 入库数量 | 本次入库 | 类型 | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 6591 | BHGZ-202607010011 | 300封油板 | URS3042Z-07-01 | 741 | 1 | 1 | 0 | 1 | 自制件 | + +结论: + +- 改制任务在完成生产后,可以进入现有 `仓储管理_自制件入库_查询` 查询结果。 +- 页面层面具备被选择并执行自制件入库的条件。 + +## 6. 入库执行逻辑分析 + +现有自制件入库提交过程: + +```text +仓储管理_自制件入库_循环执行 +``` + +关键逻辑: + +```sql +INSERT INTO 库存管理_物料与货位对照表 +( + 物料流水号, + 货位流水号, + 货位存量, + 操作日期, + 工艺计划流水号 +) +VALUES +( + @物料流水号, + @货位流水号, + @实际到货数量, + GETDATE(), + @工艺计划流水号 +); + +INSERT INTO 库存管理_自制件_入库记录 +( + 工艺计划流水号, + 实际到货数量, + 入库人员流水号, + 入库时间, + 货位流水号 +) +VALUES +( + @工艺计划流水号, + @实际到货数量, + @入库人员流水号, + GETDATE(), + @货位流水号 +); + +UPDATE 车间生产管理工艺_零件工艺计划 +SET 入库数量 = ISNULL(入库数量,0) + @实际到货数量 +WHERE 工艺计划流水号 = @工艺计划流水号; +``` + +该过程会: + +- 增加货位库存。 +- 增加累计库存。 +- 写入自制件入库记录。 +- 回写工艺计划入库数量。 +- 入库数量达到生产数量减报废数量时,将工艺计划状态更新为入库完成。 + +## 7. 风险发现 + +### 7.1 入库可执行,但可能入到原物料流水号 + +当前改制任务查询结果中,虽然视图显示了改制后的零件名称和零件图号,但 `物料流水号` 仍来自原基本件关联的物料。 + +抽样结果: + +| 改制订单编号 | 改制零件图号 | 工艺计划流水号 | 物料流水号 | 当前物料代号 | 结论 | +| --- | --- | --- | --- | --- | --- | +| BHGZ-202607010011 | URS3042Z-07-01 | 6591 | 741 | URS2267Z-04 | 不一致 | +| BHGZ-202606270010 | XT40-2-BT40-14.09-G | 6590 | 1716 | XT40-MF-05.08 | 不一致 | +| BHGZ-202606260009 | XT20-02-G | 6589 | 1251 | XT20-09 | 不一致 | + +影响: + +- 如果直接使用现有入库流程,库存可能增加到原基本件物料,而不是改制后的目标零件物料。 +- 页面显示看起来是改制零件,但库存台账实际使用的是原 `物料流水号`。 + +## 8. 测试结论 + +### 8.1 能否正常进入入库流程 + +可以。 + +完成生产后,只要满足: + +```sql +完成数量 > 入库数量 +``` + +改制任务可以被 `仓储管理_自制件入库_查询` 查出,并进入现有自制件入库页面。 + +### 8.2 能否直接认为入库完全正确 + +不能。 + +当前链路存在关键风险: + +```text +显示字段使用改制零件信息 +库存入库仍使用原物料流水号 +``` + +因此只能说“流程可进入入库”,但不能确认“库存入到正确改制物料”。 + +## 9. 修复方案执行情况 + +### 9.1 已执行方案 + +已在 `技术中心_改制订单记录` 中增加改制目标物料流水号: + +```sql +ALTER TABLE dbo.技术中心_改制订单记录 +ADD 改制物料流水号 int NULL; +``` + +已修改 `技术中心_改制订单_发起改制`: + +```sql +SELECT TOP 1 + @改制物料流水号 = 物料流水号 +FROM dbo.库存管理_物料主文件_基本 +WHERE LTRIM(RTRIM(名称)) = LTRIM(RTRIM(@改制零件名称)) + AND LTRIM(RTRIM(代号)) = LTRIM(RTRIM(@改制零件图号)) + AND ISNULL(是否禁用, 0) = 0; +``` + +查不到新物料时禁止发起: + +```sql +SELECT '0' AS result, '未找到改制零件对应的新物料,请先维护物料信息' AS msg; +``` + +已修改 `车间生产管理_零件工艺计划_视图`,让以下字段优先使用改制物料: + +```text +物料流水号 +物料编码 +代号 +货位流水号 +货位名称 +单位 +``` + +同时保留改制订单编号、改制零件名称、改制零件图号的优先显示。 + +### 9.2 当前验证结果 + +结构验证: + +| 检查项 | 结果 | +| --- | --- | +| 改制物料字段存在 | 1 | +| 发起过程已包含改制物料 | 1 | +| 生产任务视图已关联改制物料 | 1 | + +历史数据: + +| 未删除改制记录数 | 未维护改制物料数 | 已维护改制物料数 | +| --- | --- | --- | +| 11 | 11 | 0 | + +说明: + +- 历史改制记录没有匹配到新物料流水号。 +- 原因是物料主文件中没有与历史记录的“改制零件名称 + 改制零件图号”完全匹配的可用物料。 +- 新流程已阻止继续产生该问题。 + +## 10. 后续验收项 + +| 验收项 | 状态 | 标准 | +| --- | --- | --- | +| 改制任务完成后可进入自制件入库查询 | 通过 | 事务回滚模拟已验证 | +| 改制任务入库后库存写入正确物料 | 待新数据验证 | 新流程已支持改制物料流水号,需用新发起改制订单验证 | +| 入库后工艺计划入库数量增加 | 待真实流程验证 | 入库数量应增加 | +| 入库完成后考核状态变为 4 | 待真实流程验证 | 完成数量全部入库后状态为入库 | +| 入库记录显示改制订单编号 | 待联调 | 入库记录查询需关联改制记录 | diff --git a/package.json b/package.json index 1ab9dbc4..3f90ace3 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,8 @@ "chalk": "2.4.1", "copy-webpack-plugin": "4.5.2", "css-loader": "1.0.0", + "docx-to-pdf": "^1.1.0", + "docx2pdf-converter": "^2.1.1", "eslint": "4.19.1", "eslint-friendly-formatter": "4.0.1", "eslint-loader": "2.0.0", diff --git a/sql/三楼仓库可视化_存储过程.sql b/sql/三楼仓库可视化_存储过程.sql new file mode 100644 index 00000000..66f3921d --- /dev/null +++ b/sql/三楼仓库可视化_存储过程.sql @@ -0,0 +1,94 @@ +-- 三楼仓库可视化 - 库位查询存储过程 +-- 创建时间: 2026-06-30 +-- 说明: 查询三楼仓库库位列表及状态(三段式库位编码: 排号-列号-层号) +-- 状态: 0=空闲, 1=有物料无库存, 2=有库存 +-- 矩阵布局: 竖向排号,横向列号 + +IF EXISTS (SELECT name FROM sys.procedures WHERE name = '仓储管理_三楼仓库库位_查询数据') + DROP PROCEDURE 仓储管理_三楼仓库库位_查询数据 +GO + +CREATE PROCEDURE [dbo].[仓储管理_三楼仓库库位_查询数据] + @排号_check bit = 0, + @排号 nvarchar(50) = NULL, + @库位编号_check bit = 0, + @库位编号 nvarchar(50) = NULL, + @库位状态_check bit = 0, + @库位状态 int = NULL +AS +BEGIN + SET NOCOUNT ON; + + SELECT + h.货位名称 AS 库位编号, + h.货位名称 AS 库位名称, + CASE + WHEN EXISTS (SELECT 1 FROM 库存管理_物料与货位对照表 ml WHERE ml.货位流水号 = h.货位流水号 AND ml.货位存量 > 0) THEN 2 + WHEN EXISTS (SELECT 1 FROM 库存管理_物料主文件_基本 m WHERE m.货位流水号 = h.货位流水号) THEN 1 + ELSE 0 + END AS 状态, + PARSENAME(REPLACE(h.货位名称, '-', '.'), 3) AS 排号, + CAST(PARSENAME(REPLACE(h.货位名称, '-', '.'), 2) AS int) AS 列号, + PARSENAME(REPLACE(h.货位名称, '-', '.'), 1) AS 层号, + h.货位流水号 + INTO #TempLocations + FROM 库存管理_货位主文件 h + WHERE LEN(h.货位名称) - LEN(REPLACE(h.货位名称, '-', '')) = 2 + AND ISNUMERIC(PARSENAME(REPLACE(h.货位名称, '-', '.'), 3)) = 1 + + DECLARE @sql nvarchar(4000) + SET @sql = 'SELECT 库位编号, 库位名称, 状态, 排号, 列号, 层号, 货位流水号 FROM #TempLocations WHERE 1=1' + + IF @排号_check = 1 AND @排号 IS NOT NULL + SET @sql = @sql + ' AND 排号 = @p_row' + + IF @库位编号_check = 1 AND @库位编号 IS NOT NULL + SET @sql = @sql + ' AND 库位编号 LIKE ''%'' + @p_code + ''%''' + + IF @库位状态_check = 1 AND @库位状态 IS NOT NULL + SET @sql = @sql + ' AND 状态 = @p_status' + + SET @sql = @sql + ' ORDER BY 排号, 列号, 层号' + + EXEC sp_executesql @sql, + N'@p_row nvarchar(50), @p_code nvarchar(50), @p_status int', + @p_row = @排号, @p_code = @库位编号, @p_status = @库位状态 + + DROP TABLE #TempLocations +END +GO + + +-- 三楼仓库可视化 - 库位物料查询存储过程 +-- 创建时间: 2026-06-30 +-- 说明: 按库位编号查询三楼仓库库位上的物料明细 + +IF EXISTS (SELECT name FROM sys.procedures WHERE name = '仓储管理_三楼仓库库位物料_查询数据') + DROP PROCEDURE 仓储管理_三楼仓库库位物料_查询数据 +GO + +CREATE PROCEDURE [dbo].[仓储管理_三楼仓库库位物料_查询数据] + @库位编号_check bit = 0, + @库位编号 nvarchar(50) = NULL +AS +BEGIN + SET NOCOUNT ON; + + IF @库位编号_check = 1 AND @库位编号 IS NOT NULL + BEGIN + SELECT + m.物料编码 AS 物料编号, + m.名称 AS 物料名称, + m.代号 AS 图号, + m.规格 AS 规格型号, + ISNULL(ml.货位存量, 0) AS 库存数量, + ISNULL(m.库存计量单位, '台') AS 单位, + ISNULL(ml.批次号, '') AS 批次 + FROM 库存管理_货位主文件 h + INNER JOIN 库存管理_物料主文件_基本 m ON h.货位流水号 = m.货位流水号 + LEFT JOIN 库存管理_物料与货位对照表 ml ON m.物料流水号 = ml.物料流水号 AND ml.货位流水号 = h.货位流水号 + WHERE h.货位名称 = @库位编号 + ORDER BY m.物料编码 + END +END +GO diff --git a/sql/仓储管理_入库记录_入库单去重.sql b/sql/仓储管理_入库记录_入库单去重.sql new file mode 100644 index 00000000..c1f7c84a --- /dev/null +++ b/sql/仓储管理_入库记录_入库单去重.sql @@ -0,0 +1,238 @@ +-- 入库记录查询关联入库单去重修正 +-- 修改人:Ld 修改时间:2026-07-02 16:50:22; + +ALTER PROCEDURE [dbo].[仓储管理_入库记录_查询] +@物料名称_check bit = null, +@物料名称 nvarchar(50)=null, +@物料编码_check bit = null, +@物料编码 nvarchar(50) = null, +@订单号_check bit = null, +@订单号 nvarchar(50) = null, +@类型_check bit = null, +@类型 nvarchar(50) = null, +@入库时间_check bit = null, +@开始时间 datetime = null, +@结束时间 datetime = null, +@采购合同_check bit = null, +@采购合同流水号 int = null, +@供应商_check bit = null, +@供应商名称 nvarchar(50) = null, +@排序名称 int =null, +@排序方式 int =null, +@入库单号_check bit = null, +@入库单号 varchar(50) = null + AS + +declare @selectStr nvarchar(4000) +declare @selectStrWhere nvarchar(4000) + +set @selectStr = +-- 修改人:Ld 修改时间:2026-07-02 16:50:22; 入库单先按采购合同流水号聚合,避免一合同多入库单行导致入库记录重复。 +' select A.*,1 as 打印条码数,库存管理_物料主文件_基本.物料编码,采购管理_供应商.供应商编号,货位名称,isnull(累计库存,0) as 库存,入库单去重.入库单号 from (SELECT * +FROM 仓储管理_采购入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_自制入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_退料入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_通用入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_耗材采购入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_备货入库记录_视图) AS A LEFT JOIN +库存管理_物料主文件_基本 ON A.物料流水号 = 库存管理_物料主文件_基本.物料流水号 LEFT JOIN +采购管理_供应商 ON A.供应商流水号 = 采购管理_供应商.供应商流水号 LEFT JOIN +库存管理_货位主文件 ON 库存管理_物料主文件_基本.货位流水号 = 库存管理_货位主文件.货位流水号 LEFT JOIN +库存管理_外购件累计库存 ON 库存管理_物料主文件_基本.物料流水号 = 库存管理_外购件累计库存.物料流水号 LEFT JOIN +(SELECT 采购合同流水号, MAX(入库单号) AS 入库单号 FROM 仓储管理_入库单 GROUP BY 采购合同流水号) AS 入库单去重 ON A.采购合同流水号 = 入库单去重.采购合同流水号 ' + +set @selectStrWhere = 'where 1 = 1 ' + +if(@物料名称_check = 1) + set @selectStrWhere = @selectStrWhere+' and replace(isnull(物料名称,''''),'' '','''') + replace(isnull(图号或型号,''''),'' '','''') + 批次编号 like + ''%'' + replace(@物料名称,'' '','''') + ''%'' ' +if(@物料编码_check = 1) + set @selectStrWhere = @selectStrWhere+' and replace(isnull(库存管理_物料主文件_基本.物料编码,''''),'' '','''') like + ''%'' + replace(@物料编码,'' '','''') + ''%'' ' +if(@入库时间_check = 1) + set @selectStrWhere = @selectStrWhere+' and 入库日期 >=@开始时间 and 入库日期 <=@结束时间 ' +if(@订单号_check = 1) + set @selectStrWhere = @selectStrWhere+' and 订单号 like + ''%'' + @订单号 + ''%'' ' +if(@类型_check = 1) + set @selectStrWhere = @selectStrWhere+' and A.类型 = @类型 ' +if(@采购合同_check = 1) + set @selectStrWhere = @selectStrWhere+' and A.采购合同流水号 = @采购合同流水号 ' +if(@供应商_check = 1) + set @selectStrWhere = @selectStrWhere+' and 供应商 = @供应商名称 ' +if(@入库单号_check = 1) + set @selectStrWhere = @selectStrWhere+' and 入库单号 like + ''%'' + @入库单号 + ''%'' ' + +if @排序名称 = 1 +begin + if @排序方式 = 1 + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 物料编码 DESC' + end + else + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 物料编码 ASC' + end +end +else if @排序名称 = 2 +begin + if @排序方式 = 1 + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 物料名称 DESC' + end + else + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 物料名称 ASC' + end +end +else if @排序名称 = 3 +begin + if @排序方式 = 1 + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 图号或型号 DESC' + end + else + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 图号或型号 ASC' + end +end +else if @排序名称 = 4 +begin + if @排序方式 = 1 + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 货位名称 DESC' + end + else + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 货位名称 ASC' + end +end +else if @排序名称 = 5 +begin + if @排序方式 = 1 + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 批次编号 DESC' + end + else + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 批次编号 ASC' + end +end +else if @排序名称 = 6 +begin + if @排序方式 = 1 + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 供应商编号 DESC' + end + else + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 供应商编号 ASC' + end +end +else if @排序名称 = 7 +begin + if @排序方式 = 1 + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 采购合同编号 DESC' + end + else + begin + set @selectStr = @selectStr+@selectStrWhere+'order by 采购合同编号 ASC' + end +end +else +begin + set @selectStr = @selectStr+@selectStrWhere + ' order by 入库日期 desc ' +end + +EXEC sp_executesql @selectStr,N'@物料名称 nvarchar(50),@物料编码 nvarchar(50),@开始时间 datetime,@结束时间 datetime,@订单号 nvarchar(50),@类型 nvarchar(50),@采购合同流水号 int,@供应商名称 nvarchar(50),@入库单号 nvarchar(50) ', +@物料名称,@物料编码,@开始时间,@结束时间,@订单号,@类型,@采购合同流水号,@供应商名称,@入库单号 +GO + +ALTER PROCEDURE [dbo].[仓储管理_入库记录_导出表格_查询] +@入库单号_check bit = null, +@入库单号 nvarchar(50) = null, +@物料名称_check bit = null, +@物料名称 nvarchar(50)=null, +@物料编码_check bit = null, +@物料编码 nvarchar(50) = null, +@订单号_check bit = null, +@订单号 nvarchar(50) = null, +@类型_check bit = null, +@类型 nvarchar(50) = null, +@入库时间_check bit = null, +@开始时间 datetime = null, +@结束时间 datetime = null, +@采购合同_check bit = null, +@采购合同流水号 int = null, +@供应商_check bit = null, +@供应商名称 nvarchar(50) = null + AS + +select '入库记录_'+replace(replace(replace(CONVERT(nvarchar(19),GETDATE(),21),':',''),'-',''),' ','-') as tablename,'15' as tabletype + +select 256*15 as 类型,256*30 as 物料编号,256*30 as 物料名称,256*20 as [图号/型号],256*15 as 单位,256*15 as 入库数,256*15 as 库位,246*20 as 入库日期,256*30 as 入库单号, +256*30 as 批次编号,256*15 as 供应商编号,256*30 as 供应商,256*20 as 采购合同,256*30 as 订单号,256*20 as [产品/组件名称],256*20 as 采购备注 + +select 0 as 类型,0 as 物料编号,0 as 物料名称,0 as [图号/型号],0 as 单位,1 as 入库数,0 as 库位,0 as 入库日期,0 as 入库单号 +,0 as 批次编号,0 as 供应商编号,0 as 供应商,0 as 采购合同,0 as 订单号,0 as [产品/组件名称],0 as 采购备注 + +declare @selectStr nvarchar(4000) +declare @selectStrWhere nvarchar(4000) + +set @selectStr = +-- 修改人:Ld 修改时间:2026-07-02 16:50:22; 入库单先按采购合同流水号聚合,保持导出与页面查询去重口径一致。 +' select A.类型,库存管理_物料主文件_基本.物料编码 AS 物料编号,A.物料名称,A.图号或型号 AS [图号/型号],A.单位,A.入库数,货位名称,A.入库日期, +A.批次编号,采购管理_供应商.供应商编号,A.供应商,A.采购合同编号 AS 采购合同,A.订单号,A.产品名称 AS [产品/组件名称],A.备注,入库单去重.入库单号 from (SELECT * +FROM 仓储管理_采购入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_自制入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_退料入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_通用入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_耗材采购入库记录_视图 +UNION ALL +SELECT * +FROM 仓储管理_备货入库记录_视图) AS A LEFT JOIN +库存管理_物料主文件_基本 ON A.物料流水号 = 库存管理_物料主文件_基本.物料流水号 LEFT JOIN +采购管理_供应商 ON A.供应商流水号 = 采购管理_供应商.供应商流水号 LEFT JOIN +库存管理_货位主文件 ON 库存管理_物料主文件_基本.货位流水号 = 库存管理_货位主文件.货位流水号 LEFT JOIN +(SELECT 采购合同流水号, MAX(入库单号) AS 入库单号 FROM 仓储管理_入库单 GROUP BY 采购合同流水号) AS 入库单去重 ON A.采购合同流水号 = 入库单去重.采购合同流水号 ' + +set @selectStrWhere = 'where 1 = 1 ' + +if(@物料名称_check = 1) + set @selectStrWhere = @selectStrWhere+' and replace(isnull(物料名称,''''),'' '','''') + replace(isnull(图号或型号,''''),'' '','''') like + ''%'' + replace(@物料名称,'' '','''') + ''%'' ' +if(@物料编码_check = 1) + set @selectStrWhere = @selectStrWhere+' and replace(isnull(库存管理_物料主文件_基本.物料编码,''''),'' '','''') like + ''%'' + replace(@物料编码,'' '','''') + ''%'' ' +if(@入库时间_check = 1) + set @selectStrWhere = @selectStrWhere+' and 入库日期 >=@开始时间 and 入库日期 <=@结束时间 ' +if(@订单号_check = 1) + set @selectStrWhere = @selectStrWhere+' and 订单号 like + ''%'' + @订单号 + ''%'' ' +if(@类型_check = 1) + set @selectStrWhere = @selectStrWhere+' and A.类型 = @类型 ' +if(@采购合同_check = 1) + set @selectStrWhere = @selectStrWhere+' and 采购合同流水号 = @采购合同流水号 ' +if(@供应商_check = 1) + set @selectStrWhere = @selectStrWhere+' and 供应商 = @供应商名称 ' +if(@入库单号_check = 1) + set @selectStrWhere = @selectStrWhere+' and 入库单号 like + ''%'' + @入库单号 + ''%'' ' + +set @selectStr = @selectStr+@selectStrWhere+'order by 入库日期 DESC' + +EXEC sp_executesql @selectStr,N'@物料名称 nvarchar(50),@物料编码 nvarchar(50),@开始时间 datetime,@结束时间 datetime,@订单号 nvarchar(50),@类型 nvarchar(50),@采购合同流水号 int,@供应商名称 nvarchar(50),@入库单号 nvarchar(50) ', +@物料名称,@物料编码,@开始时间,@结束时间,@订单号,@类型,@采购合同流水号,@供应商名称,@入库单号 +GO diff --git a/sql/工序工价_存储过程.sql b/sql/工序工价_存储过程.sql new file mode 100644 index 00000000..c072f382 --- /dev/null +++ b/sql/工序工价_存储过程.sql @@ -0,0 +1,1037 @@ +USE [ERPTOOL_JY_20250826Back] +GO + +SET ANSI_NULLS ON +GO + +SET QUOTED_IDENTIFIER ON +GO + +-- 工序工价基础表,维护现场确认的 9 个工价字段;修改人:Ld 修改时间:2026-07-03 08:02:29; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NULL +BEGIN + CREATE TABLE [dbo].[车间生产管理工艺_工序工价]( + [工价流水号] [int] IDENTITY(1,1) NOT NULL, + [工序流水号] [int] NULL, + [工艺名称] [nvarchar](100) NOT NULL, + [工序名称] [nvarchar](100) NOT NULL, + [零件名称] [nvarchar](100) NOT NULL, + [图号] [nvarchar](100) NOT NULL, + [机动时间s] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_机动时间s] DEFAULT ((0)), + [辅助时间s] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_辅助时间s] DEFAULT ((0)), + [总时间s] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_总时间s] DEFAULT ((0)), + [单装数量(件)] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_单装数量件] DEFAULT ((0)), + [操作台数] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_操作台数] DEFAULT ((0)), + [日产能(件)] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_日产能件] DEFAULT ((0)), + [最终单价(元/件)] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_最终单价元件] DEFAULT ((0)), + [生效日期] [date] NULL, + [变更次数] [int] NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_变更次数] DEFAULT ((0)), + [是否启用] [bit] NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_是否启用] DEFAULT ((1)), + [备注] [nvarchar](500) NULL, + [创建人] [nvarchar](50) NULL, + [创建时间] [datetime] NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_创建时间] DEFAULT (GETDATE()), + [修改人] [nvarchar](50) NULL, + [修改时间] [datetime] NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_修改时间] DEFAULT (GETDATE()), + [计价方式] [nvarchar](20) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_计价方式] DEFAULT (N'按件'), + [单件工价] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_单件工价] DEFAULT ((0)), + [单时工价] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_单时工价] DEFAULT ((0)), + [准结工价] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_准结工价] DEFAULT ((0)), + [难度系数] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_难度系数] DEFAULT ((1)), + [质量系数] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_质量系数] DEFAULT ((1)), + [设备系数] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_设备系数] DEFAULT ((1)), + [失效日期] [date] NULL, + CONSTRAINT [PK_车间生产管理工艺_工序工价] PRIMARY KEY CLUSTERED ([工价流水号] ASC) + ); +END +GO + +-- 兼容已建旧表,补齐现场确认字段;修改人:Ld 修改时间:2026-07-03 08:02:29; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NOT NULL AND COL_LENGTH(N'[dbo].[车间生产管理工艺_工序工价]', N'机动时间s') IS NULL + ALTER TABLE [dbo].[车间生产管理工艺_工序工价] ADD [机动时间s] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_机动时间s] DEFAULT ((0)); +GO +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NOT NULL AND COL_LENGTH(N'[dbo].[车间生产管理工艺_工序工价]', N'辅助时间s') IS NULL + ALTER TABLE [dbo].[车间生产管理工艺_工序工价] ADD [辅助时间s] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_辅助时间s] DEFAULT ((0)); +GO +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NOT NULL AND COL_LENGTH(N'[dbo].[车间生产管理工艺_工序工价]', N'总时间s') IS NULL + ALTER TABLE [dbo].[车间生产管理工艺_工序工价] ADD [总时间s] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_总时间s] DEFAULT ((0)); +GO +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NOT NULL AND COL_LENGTH(N'[dbo].[车间生产管理工艺_工序工价]', N'单装数量(件)') IS NULL + ALTER TABLE [dbo].[车间生产管理工艺_工序工价] ADD [单装数量(件)] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_单装数量件] DEFAULT ((0)); +GO +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NOT NULL AND COL_LENGTH(N'[dbo].[车间生产管理工艺_工序工价]', N'操作台数') IS NULL + ALTER TABLE [dbo].[车间生产管理工艺_工序工价] ADD [操作台数] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_操作台数] DEFAULT ((0)); +GO +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NOT NULL AND COL_LENGTH(N'[dbo].[车间生产管理工艺_工序工价]', N'日产能(件)') IS NULL + ALTER TABLE [dbo].[车间生产管理工艺_工序工价] ADD [日产能(件)] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_日产能件] DEFAULT ((0)); +GO +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NOT NULL AND COL_LENGTH(N'[dbo].[车间生产管理工艺_工序工价]', N'最终单价(元/件)') IS NULL + ALTER TABLE [dbo].[车间生产管理工艺_工序工价] ADD [最终单价(元/件)] [decimal](18, 4) NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_最终单价元件] DEFAULT ((0)); +GO +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NOT NULL AND COL_LENGTH(N'[dbo].[车间生产管理工艺_工序工价]', N'变更次数') IS NULL + ALTER TABLE [dbo].[车间生产管理工艺_工序工价] ADD [变更次数] [int] NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价_变更次数] DEFAULT ((0)); +GO + +-- 工序流水号唯一索引,避免同一工序重复维护当前工价;修改人:Ld 修改时间:2026-07-03 08:02:29; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]', N'U') IS NOT NULL +AND NOT EXISTS ( + SELECT 1 + FROM sys.indexes + WHERE name = N'UX_车间生产管理工艺_工序工价_工序流水号' + AND object_id = OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价]') +) +BEGIN + CREATE UNIQUE NONCLUSTERED INDEX [UX_车间生产管理工艺_工序工价_工序流水号] + ON [dbo].[车间生产管理工艺_工序工价]([工序流水号]) + WHERE [工序流水号] IS NOT NULL; +END +GO + +-- 工序工价历史表,仅记录最终单价前后数据;修改人:Ld 修改时间:2026-07-06 09:27:09; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价历史记录]', N'U') IS NULL +BEGIN + CREATE TABLE [dbo].[车间生产管理工艺_工序工价历史记录]( + [历史流水号] [int] IDENTITY(1,1) NOT NULL, + [工价流水号] [int] NULL, + [工序流水号] [int] NULL, + [工艺名称] [nvarchar](100) NULL, + [工序名称] [nvarchar](100) NULL, + [零件名称] [nvarchar](100) NULL, + [图号] [nvarchar](100) NULL, + [操作类型] [nvarchar](20) NOT NULL, + [变更前] [nvarchar](max) NULL, + [变更后] [nvarchar](max) NULL, + [操作人] [nvarchar](50) NULL, + [操作时间] [datetime] NOT NULL CONSTRAINT [DF_车间生产管理工艺_工序工价历史记录_操作时间] DEFAULT (GETDATE()), + [备注] [nvarchar](500) NULL, + CONSTRAINT [PK_车间生产管理工艺_工序工价历史记录] PRIMARY KEY CLUSTERED ([历史流水号] ASC) + ); +END +GO + +-- 清理旧历史中的多字段内容,历史弹窗只保留最终单价数据;修改人:Ld 修改时间:2026-07-06 09:27:09; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价历史记录]', N'U') IS NOT NULL +BEGIN + UPDATE [dbo].[车间生产管理工艺_工序工价历史记录] + SET 变更前 = CASE + WHEN 变更前 IS NULL OR 变更前 = N'' THEN 变更前 + WHEN CHARINDEX(N'最终单价(元/件)=', 变更前) > 0 THEN + SUBSTRING( + 变更前, + CHARINDEX(N'最终单价(元/件)=', 变更前), + CASE + WHEN CHARINDEX(N';', 变更前 + N';', CHARINDEX(N'最终单价(元/件)=', 变更前)) > 0 + THEN CHARINDEX(N';', 变更前 + N';', CHARINDEX(N'最终单价(元/件)=', 变更前)) - CHARINDEX(N'最终单价(元/件)=', 变更前) + ELSE LEN(变更前) + END + ) + ELSE 变更前 + END, + 变更后 = CASE + WHEN 变更后 IS NULL OR 变更后 = N'' THEN 变更后 + WHEN CHARINDEX(N'最终单价(元/件)=', 变更后) > 0 THEN + SUBSTRING( + 变更后, + CHARINDEX(N'最终单价(元/件)=', 变更后), + CASE + WHEN CHARINDEX(N';', 变更后 + N';', CHARINDEX(N'最终单价(元/件)=', 变更后)) > 0 + THEN CHARINDEX(N';', 变更后 + N';', CHARINDEX(N'最终单价(元/件)=', 变更后)) - CHARINDEX(N'最终单价(元/件)=', 变更后) + ELSE LEN(变更后) + END + ) + ELSE 变更后 + END + WHERE (变更前 LIKE N'%最终单价(元/件)=%' AND 变更前 LIKE N'%;%') + OR (变更后 LIKE N'%最终单价(元/件)=%' AND 变更后 LIKE N'%;%'); + + -- 修改人:Ld 修改时间:2026-07-06 09:27:09; 兼容早期历史中的单件工价字段并统一为最终单价 + UPDATE [dbo].[车间生产管理工艺_工序工价历史记录] + SET 变更前 = CASE + WHEN 变更前 IS NULL OR 变更前 = N'' THEN 变更前 + WHEN CHARINDEX(N'单件工价=', 变更前) > 0 THEN + N'最终单价(元/件)=' + SUBSTRING( + 变更前, + CHARINDEX(N'单件工价=', 变更前) + LEN(N'单件工价='), + CASE + WHEN CHARINDEX(N';', 变更前 + N';', CHARINDEX(N'单件工价=', 变更前)) > 0 + THEN CHARINDEX(N';', 变更前 + N';', CHARINDEX(N'单件工价=', 变更前)) - CHARINDEX(N'单件工价=', 变更前) - LEN(N'单件工价=') + ELSE LEN(变更前) + END + ) + ELSE 变更前 + END, + 变更后 = CASE + WHEN 变更后 IS NULL OR 变更后 = N'' THEN 变更后 + WHEN CHARINDEX(N'单件工价=', 变更后) > 0 THEN + N'最终单价(元/件)=' + SUBSTRING( + 变更后, + CHARINDEX(N'单件工价=', 变更后) + LEN(N'单件工价='), + CASE + WHEN CHARINDEX(N';', 变更后 + N';', CHARINDEX(N'单件工价=', 变更后)) > 0 + THEN CHARINDEX(N';', 变更后 + N';', CHARINDEX(N'单件工价=', 变更后)) - CHARINDEX(N'单件工价=', 变更后) - LEN(N'单件工价=') + ELSE LEN(变更后) + END + ) + ELSE 变更后 + END + WHERE 变更前 LIKE N'%单件工价=%' + OR 变更后 LIKE N'%单件工价=%'; +END +GO + +-- 工序工价分页查询,参考制定工艺组件订单、产品、零件数据源后再展开有工序名称的数据;修改人:Ld 修改时间:2026-07-06 09:00:29; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价_查询数据]', N'P') IS NOT NULL + DROP PROCEDURE [dbo].[车间生产管理工艺_工序工价_查询数据]; +GO + +CREATE PROCEDURE [dbo].[车间生产管理工艺_工序工价_查询数据] + @订单流水号_check INT = 0, + @订单流水号 INT = NULL, + @组件流水号_check INT = 0, + @组件流水号 INT = NULL, + @工艺计划流水号_check INT = 0, + @工艺计划流水号 INT = NULL, + @工艺名称_check INT = 0, + @工艺名称 NVARCHAR(100) = N'', + @工序名称_check INT = 0, + @工序名称 NVARCHAR(100) = N'', + @零件名称_check INT = 0, + @零件名称 NVARCHAR(100) = N'', + @图号_check INT = 0, + @图号 NVARCHAR(100) = N'', + @是否启用_check INT = 0, + @是否启用 NVARCHAR(20) = N'', + @PageCurrent INT = 1, + @PageSize INT = 1000 +AS +BEGIN + SET NOCOUNT ON; + + IF @PageCurrent IS NULL OR @PageCurrent < 1 SET @PageCurrent = 1; + -- 修改人:Ld 修改时间:2026-07-06 08:52:37; + -- 工序工价数据超过 100 条,默认页大小放大,页面仍可按分页参数控制 + IF @PageSize IS NULL OR @PageSize < 1 SET @PageSize = 1000; + + ;WITH PlanData AS ( + -- 修改人:Ld 修改时间:2026-07-06 08:36:02; + -- 与制定工艺组件订单、产品、零件选择保持同一工艺计划来源口径 + SELECT gp.* + FROM [dbo].[车间生产管理_零件工艺计划_视图] gp + WHERE gp.考核状态 >= 1 + AND (@订单流水号_check = 0 OR gp.订单流水号 = @订单流水号) + AND (@组件流水号_check = 0 OR gp.组件流水号 = @组件流水号) + AND (@工艺计划流水号_check = 0 OR gp.工艺计划流水号 = @工艺计划流水号) + AND (@零件名称_check = 0 OR gp.零件名称 + gp.零件图号 LIKE N'%' + @零件名称 + N'%') + AND (@图号_check = 0 OR gp.零件图号 LIKE N'%' + @图号 + N'%') + ), + ProcessData AS ( + SELECT + ROW_NUMBER() OVER ( + ORDER BY gp.工艺更新时间 DESC, gp.工艺计划流水号 DESC, gx.工序顺序 ASC, gx.工序流水号 ASC + ) AS RowNum, + price.工价流水号, + gx.工序流水号, + gx.工艺计划流水号, + gp.订单号, + gp.产品名称, + base.工艺名称 AS 工艺名称, + base.工艺名称 AS 工序名称, + gp.零件名称, + gp.零件图号 AS 图号, + gx.工序顺序, + gx.定额工时, + gx.准结工时, + ISNULL(price.[机动时间s], 0) AS [机动时间s], + ISNULL(price.[辅助时间s], 0) AS [辅助时间s], + ISNULL(price.[总时间s], 0) AS [总时间s], + ISNULL(price.[单装数量(件)], 0) AS [单装数量(件)], + ISNULL(price.[操作台数], 0) AS [操作台数], + ISNULL(price.[日产能(件)], 0) AS [日产能(件)], + ISNULL(price.[最终单价(元/件)], 0) AS [最终单价(元/件)], + CONVERT(VARCHAR(10), price.生效日期, 23) AS 生效日期, + ISNULL(price.变更次数, 0) AS 变更次数, + ISNULL(price.是否启用, 1) AS 是否启用, + price.备注, + price.创建人, + CONVERT(VARCHAR(19), price.创建时间, 120) AS 创建时间, + price.修改人, + CONVERT(VARCHAR(19), price.修改时间, 120) AS 修改时间 + FROM PlanData gp + INNER JOIN [dbo].[车间生产管理工艺_零件工序] gx ON gp.工艺计划流水号 = gx.工艺计划流水号 + LEFT JOIN [dbo].[车间生产管理工艺_基础表_工艺名称] base ON gx.工艺编号 = base.工艺编号 + LEFT JOIN [dbo].[车间生产管理工艺_工序工价] price ON gx.工序流水号 = price.工序流水号 + WHERE NULLIF(LTRIM(RTRIM(base.工艺名称)), N'') IS NOT NULL + AND (@工艺名称_check = 0 OR base.工艺名称 LIKE N'%' + @工艺名称 + N'%') + AND (@工序名称_check = 0 OR base.工艺名称 LIKE N'%' + @工序名称 + N'%') + AND (@是否启用_check = 0 OR CAST(ISNULL(price.是否启用, 1) AS NVARCHAR(20)) = @是否启用) + ) + SELECT + 工价流水号, + 工序流水号, + 工艺计划流水号, + 订单号, + 产品名称, + 工艺名称, + 工序名称, + 零件名称, + 图号, + 工序顺序, + 定额工时, + 准结工时, + [机动时间s], + [辅助时间s], + [总时间s], + [单装数量(件)], + 操作台数, + [日产能(件)], + [最终单价(元/件)], + 生效日期, + 变更次数, + 是否启用, + 备注, + 创建人, + 创建时间, + 修改人, + 修改时间 + FROM ProcessData + WHERE RowNum BETWEEN ((@PageCurrent - 1) * @PageSize + 1) AND (@PageCurrent * @PageSize) + ORDER BY RowNum; + + SELECT COUNT(1) AS total + FROM [dbo].[车间生产管理_零件工艺计划_视图] gp + INNER JOIN [dbo].[车间生产管理工艺_零件工序] gx ON gp.工艺计划流水号 = gx.工艺计划流水号 + LEFT JOIN [dbo].[车间生产管理工艺_基础表_工艺名称] base ON gx.工艺编号 = base.工艺编号 + LEFT JOIN [dbo].[车间生产管理工艺_工序工价] price ON gx.工序流水号 = price.工序流水号 + WHERE gp.考核状态 >= 1 + AND (@订单流水号_check = 0 OR gp.订单流水号 = @订单流水号) + AND (@组件流水号_check = 0 OR gp.组件流水号 = @组件流水号) + AND (@工艺计划流水号_check = 0 OR gp.工艺计划流水号 = @工艺计划流水号) + AND NULLIF(LTRIM(RTRIM(base.工艺名称)), N'') IS NOT NULL + AND (@工艺名称_check = 0 OR base.工艺名称 LIKE N'%' + @工艺名称 + N'%') + AND (@工序名称_check = 0 OR base.工艺名称 LIKE N'%' + @工序名称 + N'%') + AND (@零件名称_check = 0 OR gp.零件名称 + gp.零件图号 LIKE N'%' + @零件名称 + N'%') + AND (@图号_check = 0 OR gp.零件图号 LIKE N'%' + @图号 + N'%') + AND (@是否启用_check = 0 OR CAST(ISNULL(price.是否启用, 1) AS NVARCHAR(20)) = @是否启用); +END +GO + +-- 工序工价新增;修改人:Ld 修改时间:2026-07-03 08:02:29; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价_增加数据]', N'P') IS NOT NULL + DROP PROCEDURE [dbo].[车间生产管理工艺_工序工价_增加数据]; +GO + +CREATE PROCEDURE [dbo].[车间生产管理工艺_工序工价_增加数据] + @工价流水号 NVARCHAR(50) = N'', + @工艺名称 NVARCHAR(100) = N'', + @工序名称 NVARCHAR(100) = N'', + @零件名称 NVARCHAR(100) = N'', + @图号 NVARCHAR(100) = N'', + @机动时间s NVARCHAR(50) = N'', + @辅助时间s NVARCHAR(50) = N'', + @总时间s NVARCHAR(50) = N'', + @单装数量件 NVARCHAR(50) = N'', + @操作台数 NVARCHAR(50) = N'', + @日产能件 NVARCHAR(50) = N'', + @最终单价元件 NVARCHAR(50) = N'', + @生效日期 NVARCHAR(50) = N'', + @变更次数 NVARCHAR(50) = N'', + @是否启用 NVARCHAR(20) = N'', + @备注 NVARCHAR(500) = N'', + @工序流水号 NVARCHAR(50) = N'', + @创建人 NVARCHAR(50) = N'', + @修改人 NVARCHAR(50) = N'' +AS +BEGIN + EXEC [dbo].[车间生产管理工艺_工序工价_编辑数据] + @工价流水号 = @工价流水号, + @工艺名称 = @工艺名称, + @工序名称 = @工序名称, + @零件名称 = @零件名称, + @图号 = @图号, + @机动时间s = @机动时间s, + @辅助时间s = @辅助时间s, + @总时间s = @总时间s, + @单装数量件 = @单装数量件, + @操作台数 = @操作台数, + @日产能件 = @日产能件, + @最终单价元件 = @最终单价元件, + @生效日期 = @生效日期, + @变更次数 = @变更次数, + @是否启用 = @是否启用, + @备注 = @备注, + @工序流水号 = @工序流水号, + @修改人 = @修改人; +END +GO + +-- 工序工价编辑,按已有工序流水号新增或更新工价记录;修改人:Ld 修改时间:2026-07-03 08:02:29; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价_编辑数据]', N'P') IS NOT NULL + DROP PROCEDURE [dbo].[车间生产管理工艺_工序工价_编辑数据]; +GO + +CREATE PROCEDURE [dbo].[车间生产管理工艺_工序工价_编辑数据] + @工价流水号 NVARCHAR(50) = N'', + @工艺名称 NVARCHAR(100) = N'', + @工序名称 NVARCHAR(100) = N'', + @零件名称 NVARCHAR(100) = N'', + @图号 NVARCHAR(100) = N'', + @机动时间s NVARCHAR(50) = N'', + @辅助时间s NVARCHAR(50) = N'', + @总时间s NVARCHAR(50) = N'', + @单装数量件 NVARCHAR(50) = N'', + @操作台数 NVARCHAR(50) = N'', + @日产能件 NVARCHAR(50) = N'', + @最终单价元件 NVARCHAR(50) = N'', + @生效日期 NVARCHAR(50) = N'', + @变更次数 NVARCHAR(50) = N'', + @是否启用 NVARCHAR(20) = N'', + @备注 NVARCHAR(500) = N'', + @工序流水号 NVARCHAR(50) = N'', + @修改人 NVARCHAR(50) = N'' +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @Id INT; + DECLARE @Safe工序流水号 INT; + DECLARE @Safe机动时间s DECIMAL(18, 4); + DECLARE @Safe辅助时间s DECIMAL(18, 4); + DECLARE @Safe总时间s DECIMAL(18, 4); + DECLARE @Safe单装数量件 DECIMAL(18, 4); + DECLARE @Safe操作台数 DECIMAL(18, 4); + DECLARE @Safe日产能件 DECIMAL(18, 4); + DECLARE @Safe最终单价元件 DECIMAL(18, 4); + DECLARE @Safe生效日期 DATE; + DECLARE @Safe变更次数 INT; + DECLARE @Safe是否启用 BIT = CASE WHEN NULLIF(@是否启用, N'') IS NULL THEN 1 WHEN @是否启用 = N'1' THEN 1 ELSE 0 END; + DECLARE @操作人 NVARCHAR(50) = NULLIF(@修改人, N''); + DECLARE @当前时间 DATETIME = GETDATE(); + DECLARE @旧数据 NVARCHAR(MAX); + DECLARE @新数据 NVARCHAR(MAX); + DECLARE @Old工序流水号 INT; + + SET @Id = CASE WHEN ISNUMERIC(NULLIF(@工价流水号, N'')) = 1 THEN CONVERT(INT, @工价流水号) ELSE NULL END; + SET @Safe工序流水号 = CASE WHEN ISNUMERIC(NULLIF(@工序流水号, N'')) = 1 THEN CONVERT(INT, @工序流水号) ELSE NULL END; + SET @Safe机动时间s = CASE WHEN ISNUMERIC(NULLIF(@机动时间s, N'')) = 1 THEN CONVERT(DECIMAL(18, 4), @机动时间s) ELSE 0 END; + SET @Safe辅助时间s = CASE WHEN ISNUMERIC(NULLIF(@辅助时间s, N'')) = 1 THEN CONVERT(DECIMAL(18, 4), @辅助时间s) ELSE 0 END; + SET @Safe总时间s = CASE WHEN ISNUMERIC(NULLIF(@总时间s, N'')) = 1 THEN CONVERT(DECIMAL(18, 4), @总时间s) ELSE 0 END; + SET @Safe单装数量件 = CASE WHEN ISNUMERIC(NULLIF(@单装数量件, N'')) = 1 THEN CONVERT(DECIMAL(18, 4), @单装数量件) ELSE 0 END; + SET @Safe操作台数 = CASE WHEN ISNUMERIC(NULLIF(@操作台数, N'')) = 1 THEN CONVERT(DECIMAL(18, 4), @操作台数) ELSE 0 END; + SET @Safe日产能件 = CASE WHEN ISNUMERIC(NULLIF(@日产能件, N'')) = 1 THEN CONVERT(DECIMAL(18, 4), @日产能件) ELSE 0 END; + SET @Safe最终单价元件 = CASE WHEN ISNUMERIC(NULLIF(@最终单价元件, N'')) = 1 THEN CONVERT(DECIMAL(18, 4), @最终单价元件) ELSE 0 END; + SET @Safe生效日期 = CASE WHEN ISDATE(NULLIF(@生效日期, N'')) = 1 THEN CONVERT(DATE, @生效日期) ELSE NULL END; + SET @Safe变更次数 = CASE WHEN ISNUMERIC(NULLIF(@变更次数, N'')) = 1 THEN CONVERT(INT, @变更次数) ELSE 0 END; + + IF @Safe工序流水号 IS NULL + BEGIN + SELECT N'0' AS result, N'工序流水号不能为空' AS message; + RETURN; + END; + + IF NULLIF(LTRIM(RTRIM(@工艺名称)), N'') IS NULL + OR NULLIF(LTRIM(RTRIM(@工序名称)), N'') IS NULL + OR NULLIF(LTRIM(RTRIM(@零件名称)), N'') IS NULL + OR NULLIF(LTRIM(RTRIM(@图号)), N'') IS NULL + BEGIN + SELECT N'0' AS result, N'工艺名称、工序名称、零件名称和图号不能为空' AS message; + RETURN; + END; + + IF @Id IS NULL + BEGIN + SELECT TOP 1 @Id = 工价流水号 + FROM [dbo].[车间生产管理工艺_工序工价] + WHERE 工序流水号 = @Safe工序流水号; + END; + + IF @Id IS NOT NULL + AND NOT EXISTS ( + SELECT 1 + FROM [dbo].[车间生产管理工艺_工序工价] + WHERE 工价流水号 = @Id + ) + BEGIN + SELECT N'0' AS result, N'工序工价记录不存在' AS message; + RETURN; + END; + + BEGIN TRY + BEGIN TRAN; + + IF @Id IS NOT NULL + BEGIN + SELECT + @Old工序流水号 = 工序流水号, + -- 修改人:Ld 修改时间:2026-07-06 09:27:09; 历史数据只存储最终单价 + @旧数据 = N'最终单价(元/件)=' + CONVERT(NVARCHAR(50), ISNULL([最终单价(元/件)], 0)) + FROM [dbo].[车间生产管理工艺_工序工价] + WHERE 工价流水号 = @Id; + + UPDATE [dbo].[车间生产管理工艺_工序工价] + SET 工序流水号 = @Safe工序流水号, + 工艺名称 = LTRIM(RTRIM(@工艺名称)), + 工序名称 = LTRIM(RTRIM(@工序名称)), + 零件名称 = LTRIM(RTRIM(@零件名称)), + 图号 = LTRIM(RTRIM(@图号)), + [机动时间s] = @Safe机动时间s, + [辅助时间s] = @Safe辅助时间s, + [总时间s] = @Safe总时间s, + [单装数量(件)] = @Safe单装数量件, + [操作台数] = @Safe操作台数, + [日产能(件)] = @Safe日产能件, + [最终单价(元/件)] = @Safe最终单价元件, + 生效日期 = @Safe生效日期, + 变更次数 = @Safe变更次数, + 是否启用 = @Safe是否启用, + 备注 = NULLIF(@备注, N''), + 计价方式 = N'按件', + 单件工价 = @Safe最终单价元件, + 修改人 = @操作人, + 修改时间 = @当前时间 + WHERE 工价流水号 = @Id; + END + ELSE + BEGIN + INSERT INTO [dbo].[车间生产管理工艺_工序工价]( + 工序流水号, + 工艺名称, + 工序名称, + 零件名称, + 图号, + [机动时间s], + [辅助时间s], + [总时间s], + [单装数量(件)], + [操作台数], + [日产能(件)], + [最终单价(元/件)], + 生效日期, + 变更次数, + 是否启用, + 备注, + 创建人, + 创建时间, + 修改人, + 修改时间, + 计价方式, + 单件工价 + ) + VALUES ( + @Safe工序流水号, + LTRIM(RTRIM(@工艺名称)), + LTRIM(RTRIM(@工序名称)), + LTRIM(RTRIM(@零件名称)), + LTRIM(RTRIM(@图号)), + @Safe机动时间s, + @Safe辅助时间s, + @Safe总时间s, + @Safe单装数量件, + @Safe操作台数, + @Safe日产能件, + @Safe最终单价元件, + @Safe生效日期, + @Safe变更次数, + @Safe是否启用, + NULLIF(@备注, N''), + @操作人, + @当前时间, + @操作人, + @当前时间, + N'按件', + @Safe最终单价元件 + ); + + SET @Id = SCOPE_IDENTITY(); + SET @Old工序流水号 = @Safe工序流水号; + SET @旧数据 = N''; + END; + + -- 修改人:Ld 修改时间:2026-07-06 09:27:09; 历史数据只存储最终单价 + SET @新数据 = N'最终单价(元/件)=' + CONVERT(NVARCHAR(50), @Safe最终单价元件); + + INSERT INTO [dbo].[车间生产管理工艺_工序工价历史记录]( + 工价流水号, + 工序流水号, + 工艺名称, + 工序名称, + 零件名称, + 图号, + 操作类型, + 变更前, + 变更后, + 操作人, + 操作时间, + 备注 + ) + VALUES ( + @Id, + ISNULL(@Safe工序流水号, @Old工序流水号), + LTRIM(RTRIM(@工艺名称)), + LTRIM(RTRIM(@工序名称)), + LTRIM(RTRIM(@零件名称)), + LTRIM(RTRIM(@图号)), + CASE WHEN @旧数据 = N'' THEN N'新增' ELSE N'编辑' END, + @旧数据, + @新数据, + @操作人, + @当前时间, + NULLIF(@备注, N'') + ); + + COMMIT TRAN; + + SELECT N'1' AS result, @Id AS 工价流水号; + END TRY + BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK TRAN; + + SELECT N'0' AS result, ERROR_MESSAGE() AS message; + END CATCH; +END +GO + +-- 工序工价停用;修改人:Ld 修改时间:2026-07-03 08:02:29; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价_删除数据]', N'P') IS NOT NULL + DROP PROCEDURE [dbo].[车间生产管理工艺_工序工价_删除数据]; +GO + +CREATE PROCEDURE [dbo].[车间生产管理工艺_工序工价_删除数据] + @工价流水号 NVARCHAR(50) = N'', + @修改人 NVARCHAR(50) = N'' +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @Id INT; + DECLARE @操作人 NVARCHAR(50) = NULLIF(@修改人, N''); + DECLARE @当前时间 DATETIME = GETDATE(); + DECLARE @旧数据 NVARCHAR(MAX); + DECLARE @工序流水号 INT; + DECLARE @工艺名称 NVARCHAR(100); + DECLARE @工序名称 NVARCHAR(100); + DECLARE @零件名称 NVARCHAR(100); + DECLARE @图号 NVARCHAR(100); + DECLARE @变更后 NVARCHAR(MAX); + + SET @Id = CASE WHEN ISNUMERIC(NULLIF(@工价流水号, N'')) = 1 THEN CONVERT(INT, @工价流水号) ELSE NULL END; + + IF @Id IS NULL + BEGIN + SELECT N'0' AS result, N'工价流水号不能为空' AS message; + RETURN; + END; + + IF NOT EXISTS ( + SELECT 1 + FROM [dbo].[车间生产管理工艺_工序工价] + WHERE 工价流水号 = @Id + ) + BEGIN + SELECT N'0' AS result, N'工序工价记录不存在' AS message; + RETURN; + END; + + BEGIN TRY + BEGIN TRAN; + + SELECT + @工序流水号 = 工序流水号, + @工艺名称 = 工艺名称, + @工序名称 = 工序名称, + @零件名称 = 零件名称, + @图号 = 图号, + -- 修改人:Ld 修改时间:2026-07-06 09:27:09; 停用历史只记录最终单价 + @旧数据 = N'最终单价(元/件)=' + CONVERT(NVARCHAR(50), ISNULL([最终单价(元/件)], 0)) + FROM [dbo].[车间生产管理工艺_工序工价] + WHERE 工价流水号 = @Id; + + UPDATE [dbo].[车间生产管理工艺_工序工价] + SET 是否启用 = 0, + 修改人 = @操作人, + 修改时间 = @当前时间 + WHERE 工价流水号 = @Id; + + -- 修改人:Ld 修改时间:2026-07-06 09:27:09; 停用历史只记录最终单价 + SET @变更后 = @旧数据; + + INSERT INTO [dbo].[车间生产管理工艺_工序工价历史记录]( + 工价流水号, + 工序流水号, + 工艺名称, + 工序名称, + 零件名称, + 图号, + 操作类型, + 变更前, + 变更后, + 操作人, + 操作时间, + 备注 + ) + VALUES ( + @Id, + @工序流水号, + @工艺名称, + @工序名称, + @零件名称, + @图号, + N'停用', + @旧数据, + @变更后, + @操作人, + @当前时间, + N'' + ); + + COMMIT TRAN; + + SELECT N'1' AS result; + END TRY + BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK TRAN; + + SELECT N'0' AS result, ERROR_MESSAGE() AS message; + END CATCH; +END +GO + +-- 工序工价复制源查询,仅返回零件名称、工序号和工艺名称;修改人:Ld 修改时间:2026-07-06 08:45:45; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价_复制源_查询数据]', N'P') IS NOT NULL + DROP PROCEDURE [dbo].[车间生产管理工艺_工序工价_复制源_查询数据]; +GO + +CREATE PROCEDURE [dbo].[车间生产管理工艺_工序工价_复制源_查询数据] + @零件图号 NVARCHAR(100) = N'' +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @源工艺计划流水号 INT; + + SELECT TOP 1 @源工艺计划流水号 = 工艺计划流水号 + FROM [dbo].[车间生产管理_零件工艺计划_视图] + WHERE 零件图号 = @零件图号 + AND 考核状态 >= 1 + ORDER BY 工艺更新时间 DESC, 工艺计划流水号 DESC; + + SELECT + gp.零件名称, + gx.工序顺序, + ISNULL(base.工艺名称, N'未设置工序') AS 工艺名称 + FROM [dbo].[车间生产管理工艺_零件工序] gx + LEFT JOIN [dbo].[车间生产管理工艺_基础表_工艺名称] base ON gx.工艺编号 = base.工艺编号 + LEFT JOIN [dbo].[车间生产管理_零件工艺计划_视图] gp ON gx.工艺计划流水号 = gp.工艺计划流水号 + WHERE gx.工艺计划流水号 = @源工艺计划流水号 + ORDER BY gx.工序顺序; +END +GO + +-- 工序工价复制,按工序号和工艺名称匹配源零件已维护工价;修改人:Ld 修改时间:2026-07-06 08:45:45; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价_复制数据]', N'P') IS NOT NULL + DROP PROCEDURE [dbo].[车间生产管理工艺_工序工价_复制数据]; +GO + +CREATE PROCEDURE [dbo].[车间生产管理工艺_工序工价_复制数据] + @目标工艺计划流水号 NVARCHAR(50) = N'', + @源零件图号 NVARCHAR(100) = N'', + @修改人 NVARCHAR(50) = N'' +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @TargetPlanId INT; + DECLARE @SourcePlanId INT; + DECLARE @操作人 NVARCHAR(50) = NULLIF(@修改人, N''); + DECLARE @当前时间 DATETIME = GETDATE(); + + SET @TargetPlanId = CASE WHEN ISNUMERIC(NULLIF(@目标工艺计划流水号, N'')) = 1 THEN CONVERT(INT, @目标工艺计划流水号) ELSE NULL END; + + IF @TargetPlanId IS NULL + BEGIN + SELECT N'0' AS result, N'目标零件不能为空' AS message; + RETURN; + END; + + SELECT TOP 1 @SourcePlanId = 工艺计划流水号 + FROM [dbo].[车间生产管理_零件工艺计划_视图] + WHERE 零件图号 = @源零件图号 + AND 考核状态 >= 1 + ORDER BY 工艺更新时间 DESC, 工艺计划流水号 DESC; + + IF @SourcePlanId IS NULL + BEGIN + SELECT N'0' AS result, N'源零件没有可复制的工序数据' AS message; + RETURN; + END; + + IF @SourcePlanId = @TargetPlanId + BEGIN + SELECT N'0' AS result, N'不能复制当前零件自身' AS message; + RETURN; + END; + + IF OBJECT_ID(N'tempdb..#CopyRows') IS NOT NULL DROP TABLE #CopyRows; + CREATE TABLE #CopyRows( + 工序流水号 INT NOT NULL, + 工艺名称 NVARCHAR(100) NOT NULL, + 工序名称 NVARCHAR(100) NOT NULL, + 零件名称 NVARCHAR(100) NOT NULL, + 图号 NVARCHAR(100) NOT NULL, + [机动时间s] DECIMAL(18, 4) NOT NULL, + [辅助时间s] DECIMAL(18, 4) NOT NULL, + [总时间s] DECIMAL(18, 4) NOT NULL, + [单装数量(件)] DECIMAL(18, 4) NOT NULL, + [操作台数] DECIMAL(18, 4) NOT NULL, + [日产能(件)] DECIMAL(18, 4) NOT NULL, + [最终单价(元/件)] DECIMAL(18, 4) NOT NULL, + 生效日期 DATE NULL, + 变更次数 INT NOT NULL, + 是否启用 BIT NOT NULL, + 备注 NVARCHAR(500) NULL + ); + + -- 修改人:Ld 修改时间:2026-07-06 08:45:45; + -- 源与目标仅按工序号和工艺名称匹配,避免带入制定工艺的其他工艺编辑数据 + INSERT INTO #CopyRows( + 工序流水号, + 工艺名称, + 工序名称, + 零件名称, + 图号, + [机动时间s], + [辅助时间s], + [总时间s], + [单装数量(件)], + [操作台数], + [日产能(件)], + [最终单价(元/件)], + 生效日期, + 变更次数, + 是否启用, + 备注 + ) + SELECT + targetGx.工序流水号, + ISNULL(targetBase.工艺名称, N'未设置工序') AS 工艺名称, + ISNULL(targetBase.工艺名称, N'未设置工序') AS 工序名称, + targetGp.零件名称, + targetGp.零件图号 AS 图号, + sourcePrice.[机动时间s], + sourcePrice.[辅助时间s], + sourcePrice.[总时间s], + sourcePrice.[单装数量(件)], + sourcePrice.[操作台数], + sourcePrice.[日产能(件)], + sourcePrice.[最终单价(元/件)], + sourcePrice.生效日期, + sourcePrice.变更次数, + sourcePrice.是否启用, + sourcePrice.备注 + FROM [dbo].[车间生产管理工艺_零件工序] targetGx + LEFT JOIN [dbo].[车间生产管理工艺_基础表_工艺名称] targetBase ON targetGx.工艺编号 = targetBase.工艺编号 + LEFT JOIN [dbo].[车间生产管理_零件工艺计划_视图] targetGp ON targetGx.工艺计划流水号 = targetGp.工艺计划流水号 + INNER JOIN [dbo].[车间生产管理工艺_零件工序] sourceGx ON sourceGx.工艺计划流水号 = @SourcePlanId + AND sourceGx.工序顺序 = targetGx.工序顺序 + LEFT JOIN [dbo].[车间生产管理工艺_基础表_工艺名称] sourceBase ON sourceGx.工艺编号 = sourceBase.工艺编号 + INNER JOIN [dbo].[车间生产管理工艺_工序工价] sourcePrice ON sourceGx.工序流水号 = sourcePrice.工序流水号 + WHERE targetGx.工艺计划流水号 = @TargetPlanId + AND ISNULL(sourceBase.工艺名称, N'未设置工序') = ISNULL(targetBase.工艺名称, N'未设置工序'); + + IF NOT EXISTS (SELECT 1 FROM #CopyRows) + BEGIN + SELECT N'0' AS result, N'源零件没有可匹配的工价记录' AS message; + RETURN; + END; + + BEGIN TRY + BEGIN TRAN; + + UPDATE price + SET price.工艺名称 = copyData.工艺名称, + price.工序名称 = copyData.工序名称, + price.零件名称 = copyData.零件名称, + price.图号 = copyData.图号, + price.[机动时间s] = copyData.[机动时间s], + price.[辅助时间s] = copyData.[辅助时间s], + price.[总时间s] = copyData.[总时间s], + price.[单装数量(件)] = copyData.[单装数量(件)], + price.[操作台数] = copyData.[操作台数], + price.[日产能(件)] = copyData.[日产能(件)], + price.[最终单价(元/件)] = copyData.[最终单价(元/件)], + price.生效日期 = copyData.生效日期, + price.变更次数 = copyData.变更次数, + price.是否启用 = copyData.是否启用, + price.备注 = copyData.备注, + price.计价方式 = N'按件', + price.单件工价 = copyData.[最终单价(元/件)], + price.修改人 = @操作人, + price.修改时间 = @当前时间 + FROM [dbo].[车间生产管理工艺_工序工价] price + INNER JOIN #CopyRows copyData ON price.工序流水号 = copyData.工序流水号; + + INSERT INTO [dbo].[车间生产管理工艺_工序工价]( + 工序流水号, + 工艺名称, + 工序名称, + 零件名称, + 图号, + [机动时间s], + [辅助时间s], + [总时间s], + [单装数量(件)], + [操作台数], + [日产能(件)], + [最终单价(元/件)], + 生效日期, + 变更次数, + 是否启用, + 备注, + 创建人, + 创建时间, + 修改人, + 修改时间, + 计价方式, + 单件工价 + ) + SELECT + copyData.工序流水号, + copyData.工艺名称, + copyData.工序名称, + copyData.零件名称, + copyData.图号, + copyData.[机动时间s], + copyData.[辅助时间s], + copyData.[总时间s], + copyData.[单装数量(件)], + copyData.[操作台数], + copyData.[日产能(件)], + copyData.[最终单价(元/件)], + copyData.生效日期, + copyData.变更次数, + copyData.是否启用, + copyData.备注, + @操作人, + @当前时间, + @操作人, + @当前时间, + N'按件', + copyData.[最终单价(元/件)] + FROM #CopyRows copyData + WHERE NOT EXISTS ( + SELECT 1 + FROM [dbo].[车间生产管理工艺_工序工价] price + WHERE price.工序流水号 = copyData.工序流水号 + ); + + INSERT INTO [dbo].[车间生产管理工艺_工序工价历史记录]( + 工价流水号, + 工序流水号, + 工艺名称, + 工序名称, + 零件名称, + 图号, + 操作类型, + 变更前, + 变更后, + 操作人, + 操作时间, + 备注 + ) + SELECT + price.工价流水号, + price.工序流水号, + price.工艺名称, + price.工序名称, + price.零件名称, + price.图号, + N'拷贝', + N'源零件图号=' + ISNULL(@源零件图号, N''), + N'最终单价(元/件)=' + CONVERT(NVARCHAR(50), price.[最终单价(元/件)]), + @操作人, + @当前时间, + N'工序工价拷贝' + FROM [dbo].[车间生产管理工艺_工序工价] price + INNER JOIN #CopyRows copyData ON price.工序流水号 = copyData.工序流水号; + + COMMIT TRAN; + + SELECT N'1' AS result, COUNT(1) AS 复制数量 + FROM #CopyRows; + END TRY + BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK TRAN; + + SELECT N'0' AS result, ERROR_MESSAGE() AS message; + END CATCH; +END +GO + +-- 工序工价历史查询,按该零件的该工序名称查看历史;修改人:Ld 修改时间:2026-07-06 09:00:29; +IF OBJECT_ID(N'[dbo].[车间生产管理工艺_工序工价_历史_查询数据]', N'P') IS NOT NULL + DROP PROCEDURE [dbo].[车间生产管理工艺_工序工价_历史_查询数据]; +GO + +CREATE PROCEDURE [dbo].[车间生产管理工艺_工序工价_历史_查询数据] + @零件名称_check INT = 0, + @零件名称 NVARCHAR(100) = N'', + @图号_check INT = 0, + @图号 NVARCHAR(100) = N'', + @工序名称_check INT = 0, + @工序名称 NVARCHAR(100) = N'', + @PageCurrent INT = 1, + @PageSize INT = 100 +AS +BEGIN + SET NOCOUNT ON; + + IF @PageCurrent IS NULL OR @PageCurrent < 1 SET @PageCurrent = 1; + IF @PageSize IS NULL OR @PageSize < 1 SET @PageSize = 100; + + ;WITH HistoryData AS ( + SELECT + ROW_NUMBER() OVER (ORDER BY 操作时间 DESC, 历史流水号 DESC) AS RowNum, + 历史流水号, + 工价流水号, + 工序流水号, + 工艺名称, + 工序名称, + 零件名称, + 图号, + 操作类型, + 变更前, + 变更后, + 操作人, + CONVERT(VARCHAR(19), 操作时间, 120) AS 操作时间, + 备注 + FROM [dbo].[车间生产管理工艺_工序工价历史记录] + WHERE (@零件名称_check = 0 OR 零件名称 = @零件名称) + AND (@图号_check = 0 OR 图号 = @图号) + AND (@工序名称_check = 0 OR 工序名称 = @工序名称) + ) + SELECT + 历史流水号, + 工价流水号, + 工序流水号, + 工艺名称, + 工序名称, + 零件名称, + 图号, + 操作类型, + 变更前, + 变更后, + 操作人, + 操作时间, + 备注 + FROM HistoryData + WHERE RowNum BETWEEN ((@PageCurrent - 1) * @PageSize + 1) AND (@PageCurrent * @PageSize) + ORDER BY RowNum; + + SELECT COUNT(1) AS total + FROM [dbo].[车间生产管理工艺_工序工价历史记录] + WHERE (@零件名称_check = 0 OR 零件名称 = @零件名称) + AND (@图号_check = 0 OR 图号 = @图号) + AND (@工序名称_check = 0 OR 工序名称 = @工序名称); +END +GO diff --git a/sql/工时统计_添加工价总价.sql b/sql/工时统计_添加工价总价.sql new file mode 100644 index 00000000..932d7e62 --- /dev/null +++ b/sql/工时统计_添加工价总价.sql @@ -0,0 +1,236 @@ +USE [ERPTOOL_JY_20250826Back] +GO + +SET ANSI_NULLS ON +GO + +SET QUOTED_IDENTIFIER ON +GO + +-- 员工工时汇总增加工价总价,工价取工序工价当前启用最终单价,总价=完成数量*工价;修改人:Ld 修改时间:2026-07-06 09:12:38; +ALTER PROCEDURE [dbo].[车间生产管理_工人工时统计_查询数据] + @开始时间 DATETIME = NULL, + @结束时间 DATETIME = NULL +AS +BEGIN + SET NOCOUNT ON; + + SELECT + SUM(a.工时) AS 加工工时, + SUM(a.完成数量) AS 总数量, + SUM(a.总价) AS 总价, + a.姓名 AS 操作者, + a.操作者编号 + FROM ( + SELECT + ISNULL(f.扫码工时, 0) AS 工时, + p.姓名, + f.操作者编号, + f.完成日期, + f.完成数量, + ISNULL(f.完成数量, 0) * ISNULL(price.工价, 0) AS 总价 + FROM dbo.设备管理_零件工序_工序完成过程情况 f + INNER JOIN dbo.人事档案管理_人员名单 p ON f.操作者编号 = p.人员编号 + OUTER APPLY ( + SELECT TOP 1 ISNULL(pp.[最终单价(元/件)], 0) AS 工价 + FROM dbo.车间生产管理工艺_工序工价 pp + WHERE pp.工序流水号 = f.工序流水号 + AND ISNULL(pp.是否启用, 1) = 1 + ORDER BY ISNULL(pp.生效日期, CONVERT(DATE, '1900-01-01')) DESC, pp.修改时间 DESC, pp.工价流水号 DESC + ) price + WHERE f.完成日期 >= @开始时间 + AND f.完成日期 <= @结束时间 + ) a + GROUP BY a.姓名, a.操作者编号; +END +GO + +-- 员工工时明细增加工价总价,明细按零件名称+图号+工序匹配工序工价;修改人:Ld 修改时间:2026-07-06 09:12:38; +ALTER PROCEDURE [dbo].[精工车间_员工工时统计_详情_查询数据] + @操作者编号 INT = 62, + @开始时间 DATETIME = NULL, + @结束时间 DATETIME = NULL, + @排序名称 INT = NULL, + @排序方式 INT = NULL +AS +BEGIN + SET NOCOUNT ON; + + SELECT + data.*, + data.加工时长 / NULLIF(data.完成数, 0) AS 单个工时, + ISNULL(price.工价, 0) AS 工价, + ISNULL(data.完成数, 0) * ISNULL(price.工价, 0) AS 总价 + FROM dbo.车间生产管理_零件工序加工时长_视图 data + OUTER APPLY ( + SELECT TOP 1 ISNULL(pp.[最终单价(元/件)], 0) AS 工价 + FROM dbo.车间生产管理工艺_工序工价 pp + WHERE pp.零件名称 = data.零件名称 + AND pp.图号 = data.图号 + AND pp.工序名称 = data.工序 + AND ISNULL(pp.是否启用, 1) = 1 + ORDER BY ISNULL(pp.生效日期, CONVERT(DATE, '1900-01-01')) DESC, pp.修改时间 DESC, pp.工价流水号 DESC + ) price + WHERE data.操作者编号 = @操作者编号 + AND data.结束加工 >= @开始时间 + AND data.结束加工 < DATEADD(DAY, 1, @结束时间) + ORDER BY + CASE WHEN @排序名称 = 1 AND @排序方式 = 1 THEN data.结束加工 END DESC, + CASE WHEN @排序名称 = 1 AND @排序方式 <> 1 THEN data.结束加工 END ASC, + CASE WHEN ISNULL(@排序名称, 0) <> 1 THEN data.结束加工 END DESC; +END +GO + +-- 设备工时汇总增加工价总价,工价取工序工价当前启用最终单价,总价=完成数量*工价;修改人:Ld 修改时间:2026-07-06 09:12:38; +ALTER PROCEDURE [dbo].[车间生产管理_设备工时统计_查询数据] + @开始时间 DATETIME = NULL, + @结束时间 DATETIME = NULL +AS +BEGIN + SET NOCOUNT ON; + + SELECT + SUM(a.工时) AS 加工工时, + a.工位号 AS 设备, + SUM(a.完成数量) AS 总数量, + SUM(a.总价) AS 总价 + FROM ( + SELECT + ISNULL(f.扫码工时, 0) AS 工时, + e.设备名称 + N'-' + f.工位号 AS 工位号, + f.完成数量, + ISNULL(f.完成数量, 0) * ISNULL(price.工价, 0) AS 总价 + FROM dbo.设备管理_零件工序_工序完成过程情况 f + INNER JOIN dbo.基础数据_设备工位点检表 e ON f.工位号 = e.工位号 + OUTER APPLY ( + SELECT TOP 1 ISNULL(pp.[最终单价(元/件)], 0) AS 工价 + FROM dbo.车间生产管理工艺_工序工价 pp + WHERE pp.工序流水号 = f.工序流水号 + AND ISNULL(pp.是否启用, 1) = 1 + ORDER BY ISNULL(pp.生效日期, CONVERT(DATE, '1900-01-01')) DESC, pp.修改时间 DESC, pp.工价流水号 DESC + ) price + WHERE f.完成日期 >= @开始时间 + AND f.完成日期 <= @结束时间 + ) a + GROUP BY a.工位号; +END +GO + +-- 设备工时明细增加工价总价,明细按零件名称+图号+工序匹配工序工价;修改人:Ld 修改时间:2026-07-06 09:12:38; +ALTER PROCEDURE [dbo].[精工车间_设备工时统计_详情_查询数据] + @设备 NVARCHAR(50) = NULL, + @开始时间 DATETIME = NULL, + @结束时间 DATETIME = NULL, + @排序名称 INT = NULL, + @排序方式 INT = NULL +AS +BEGIN + SET NOCOUNT ON; + + SELECT + data.*, + ISNULL(price.工价, 0) AS 工价, + ISNULL(data.完成数, 0) * ISNULL(price.工价, 0) AS 总价 + FROM dbo.车间生产管理_零件工序加工时长_视图 data + OUTER APPLY ( + SELECT TOP 1 ISNULL(pp.[最终单价(元/件)], 0) AS 工价 + FROM dbo.车间生产管理工艺_工序工价 pp + WHERE pp.零件名称 = data.零件名称 + AND pp.图号 = data.图号 + AND pp.工序名称 = data.工序 + AND ISNULL(pp.是否启用, 1) = 1 + ORDER BY ISNULL(pp.生效日期, CONVERT(DATE, '1900-01-01')) DESC, pp.修改时间 DESC, pp.工价流水号 DESC + ) price + WHERE data.工位号 = @设备 + AND data.结束加工 >= @开始时间 + AND data.结束加工 <= @结束时间 + ORDER BY + CASE WHEN @排序名称 = 1 AND @排序方式 = 1 THEN data.结束加工 END DESC, + CASE WHEN @排序名称 = 1 AND @排序方式 <> 1 THEN data.结束加工 END ASC, + CASE WHEN ISNULL(@排序名称, 0) <> 1 THEN data.结束加工 END DESC; +END +GO + +-- 员工工时导出增加工价总价列,保持与页面明细一致;修改人:Ld 修改时间:2026-07-06 09:12:38; +ALTER PROCEDURE [dbo].[报表_精工车间_员工工时统计_查询数据] + @开始时间 DATETIME = NULL, + @结束时间 DATETIME = NULL, + @排序名称 INT = NULL, + @排序方式 INT = NULL +AS +BEGIN + SET NOCOUNT ON; + + SELECT N'库存_' + REPLACE(REPLACE(REPLACE(CONVERT(NVARCHAR(19), GETDATE(), 21), ':', ''), '-', ''), ' ', '-') AS tablename, '17' AS tabletype; + + SELECT + 256 * 15 AS 工序, + 256 * 10 AS 工序顺序, + 256 * 30 AS 零件名称, + 256 * 30 AS 零件图号, + 256 * 20 AS 物料编码, + 256 * 10 AS 加工数, + 256 * 15 AS 加工工时M, + 256 * 10 AS 暂停时长, + 256 * 10 AS 工价, + 256 * 12 AS 总价, + 256 * 30 AS 开始加工时间, + 256 * 30 AS 完成时间, + 256 * 10 AS 操作者, + 256 * 25 AS 设备, + 246 * 25 AS 订单编号, + 246 * 25 AS 产品名称; + + SELECT + 0 AS 工序, + 1 AS 工序顺序, + 0 AS 零件名称, + 0 AS 零件图号, + 0 AS 物料编号, + 1 AS 加工数, + 1 AS 加工工时M, + 1 AS 暂停时长, + 1 AS 工价, + 1 AS 总价, + 0 AS 开始加工时间, + 0 AS 完成时间, + 0 AS 操作者, + 0 AS 设备, + 0 AS 订单编号, + 0 AS 产品名称; + + SELECT + data.工序, + data.工序顺序, + data.零件名称, + data.图号 AS 零件图号, + data.物料编码, + data.完成数 AS 加工数, + data.加工时长 AS 加工工时M, + data.暂停时间 AS 暂停时长, + ISNULL(price.工价, 0) AS 工价, + ISNULL(data.完成数, 0) * ISNULL(price.工价, 0) AS 总价, + data.开始加工 AS 开始加工时间, + data.结束加工 AS 完成时间, + data.操作者, + data.工位号 AS 设备, + data.订单编号, + data.产品名称 + FROM dbo.车间生产管理_零件工序加工时长_视图 data + OUTER APPLY ( + SELECT TOP 1 ISNULL(pp.[最终单价(元/件)], 0) AS 工价 + FROM dbo.车间生产管理工艺_工序工价 pp + WHERE pp.零件名称 = data.零件名称 + AND pp.图号 = data.图号 + AND pp.工序名称 = data.工序 + AND ISNULL(pp.是否启用, 1) = 1 + ORDER BY ISNULL(pp.生效日期, CONVERT(DATE, '1900-01-01')) DESC, pp.修改时间 DESC, pp.工价流水号 DESC + ) price + WHERE data.结束加工 >= @开始时间 + AND data.结束加工 <= @结束时间 + ORDER BY + CASE WHEN @排序名称 = 1 AND @排序方式 = 1 THEN data.结束加工 END DESC, + CASE WHEN @排序名称 = 1 AND @排序方式 <> 1 THEN data.结束加工 END ASC, + CASE WHEN ISNULL(@排序名称, 0) <> 1 THEN data.结束加工 END DESC; +END +GO diff --git a/sql/机加工MES_加工完成整修审核_查询审核.sql b/sql/机加工MES_加工完成整修审核_查询审核.sql new file mode 100644 index 00000000..c5633e0f --- /dev/null +++ b/sql/机加工MES_加工完成整修审核_查询审核.sql @@ -0,0 +1,381 @@ +-- 生产完成审核查询与审核处理 修改人:Ld 修改时间:2026-07-02 13:57:18; +IF OBJECT_ID(N'[dbo].[机加工MES_加工完成整修审核_查询数据]', N'P') IS NOT NULL + DROP PROCEDURE [dbo].[机加工MES_加工完成整修审核_查询数据]; +GO + +CREATE PROCEDURE [dbo].[机加工MES_加工完成整修审核_查询数据] + @审核状态_check INT = 0, + @审核状态 NVARCHAR(20) = N'', + @审核类型_check INT = 0, + @审核类型 NVARCHAR(50) = N'', + @操作者_check INT = 0, + @操作者 NVARCHAR(100) = N'', + @时间_check INT = 0, + @开始时间 NVARCHAR(20) = N'', + @结束时间 NVARCHAR(20) = N'', + @PageCurrent INT = 1, + @PageSize INT = 100 +AS +BEGIN + SET NOCOUNT ON; + + IF @PageCurrent IS NULL OR @PageCurrent < 1 SET @PageCurrent = 1; + IF @PageSize IS NULL OR @PageSize < 1 SET @PageSize = 100; + + ;WITH AuditData AS ( + SELECT + ROW_NUMBER() OVER ( + ORDER BY + CASE WHEN A.审核状态 = N'待审核' THEN 0 ELSE 1 END, + A.提交时间 DESC, + A.id DESC + ) AS RowNum, + A.id, + A.审核类型, + A.审核状态, + V.订单号, + V.产品名称, + V.零件名称, + V.零件图号, + V.工序, + V.工艺计划流水号, + V.数量 AS 投产数量, + V.已完成数, + V.工序顺序, + V.物料编码, + V.材料, + A.工序流水号, + A.工作者考勤编号, + 工作者.姓名 AS 工作者姓名, + A.完成数量, + A.完成类型, + A.录工票人员编号, + 录工票人员.姓名 AS 录工票人员姓名, + A.工位号, + ISNULL(SB.设备名称, A.设备名) AS 工位设备名称, + A.备注, + A.剩余工时, + A.剩余数量, + A.设备号, + A.设备名, + A.操作者, + ISNULL(操作者人员.姓名, A.操作者) AS 操作者姓名, + A.整修状态, + A.整修记录id, + A.整修方案, + CONVERT(VARCHAR(19), A.开始时间, 120) AS 开始时间, + CONVERT(VARCHAR(19), A.结束时间, 120) AS 结束时间, + CONVERT(VARCHAR(19), A.提交时间, 120) AS 提交时间, + A.审核人, + 审核人员.姓名 AS 审核人姓名, + CONVERT(VARCHAR(19), A.审核时间, 120) AS 审核时间, + A.审核意见, + A.修改人, + CONVERT(VARCHAR(19), A.修改时间, 120) AS 修改时间 + FROM [dbo].[MES_机加工MES_加工完成整修审核表] AS A + LEFT JOIN [dbo].[车间生产管理_零件工序_视图] AS V + ON A.工序流水号 = V.工序流水号 + LEFT JOIN [dbo].[人事档案管理_人员名单] AS 工作者 + ON A.工作者考勤编号 = 工作者.考勤编号 + LEFT JOIN [dbo].[人事档案管理_人员名单] AS 录工票人员 + ON A.录工票人员编号 = 录工票人员.序号 + OR A.录工票人员编号 = 录工票人员.人员编号 + LEFT JOIN [dbo].[人事档案管理_人员名单] AS 操作者人员 + ON A.操作者 = CONVERT(NVARCHAR(100), 操作者人员.人员编号) + OR A.操作者 = CONVERT(NVARCHAR(100), 操作者人员.序号) + OR A.操作者 = 操作者人员.姓名 + LEFT JOIN [dbo].[人事档案管理_人员名单] AS 审核人员 + ON A.审核人 = CONVERT(NVARCHAR(100), 审核人员.人员编号) + OR A.审核人 = CONVERT(NVARCHAR(100), 审核人员.序号) + OR A.审核人 = 审核人员.姓名 + LEFT JOIN [dbo].[基础数据_设备工位点检表] AS SB + ON A.工位号 = SB.工位号 + WHERE (@审核状态_check = 0 OR A.审核状态 = @审核状态) + AND (@审核类型_check = 0 OR A.审核类型 = @审核类型) + AND (@操作者_check = 0 OR ISNULL(操作者人员.姓名, ISNULL(A.操作者, N'')) LIKE N'%' + @操作者 + N'%') + AND (@时间_check = 0 OR CONVERT(DATE, A.提交时间) BETWEEN CONVERT(DATE, @开始时间) AND CONVERT(DATE, @结束时间)) + ) + SELECT + id, + 审核类型, + 审核状态, + 订单号, + 产品名称, + 零件名称, + 零件图号, + 工序, + 工艺计划流水号, + 投产数量, + 已完成数, + 工序顺序, + 物料编码, + 材料, + 工序流水号, + 工作者考勤编号, + 工作者姓名, + 完成数量, + 完成类型, + 录工票人员编号, + 录工票人员姓名, + 工位号, + 工位设备名称, + 备注, + 剩余工时, + 剩余数量, + 设备号, + 设备名, + 操作者, + 操作者姓名, + 整修状态, + 整修记录id, + 整修方案, + 开始时间, + 结束时间, + 提交时间, + 审核人, + 审核人姓名, + 审核时间, + 审核意见, + 修改人, + 修改时间 + FROM AuditData + WHERE RowNum BETWEEN ((@PageCurrent - 1) * @PageSize + 1) AND (@PageCurrent * @PageSize) + ORDER BY RowNum; + + SELECT COUNT(1) AS total + FROM [dbo].[MES_机加工MES_加工完成整修审核表] AS A + LEFT JOIN [dbo].[人事档案管理_人员名单] AS 操作者人员 + ON A.操作者 = CONVERT(NVARCHAR(100), 操作者人员.人员编号) + OR A.操作者 = CONVERT(NVARCHAR(100), 操作者人员.序号) + OR A.操作者 = 操作者人员.姓名 + WHERE (@审核状态_check = 0 OR A.审核状态 = @审核状态) + AND (@审核类型_check = 0 OR A.审核类型 = @审核类型) + AND (@操作者_check = 0 OR ISNULL(操作者人员.姓名, ISNULL(A.操作者, N'')) LIKE N'%' + @操作者 + N'%') + AND (@时间_check = 0 OR CONVERT(DATE, A.提交时间) BETWEEN CONVERT(DATE, @开始时间) AND CONVERT(DATE, @结束时间)); +END; +GO + +-- 生产完成审核状态更新,审核通过时接入原 MES 完工链路 修改人:Ld 修改时间:2026-07-02 14:55:23; +IF OBJECT_ID(N'[dbo].[机加工MES_加工完成整修审核_审核数据]', N'P') IS NOT NULL + DROP PROCEDURE [dbo].[机加工MES_加工完成整修审核_审核数据]; +GO + +CREATE PROCEDURE [dbo].[机加工MES_加工完成整修审核_审核数据] + @审核流水号 INT, + @审核状态 NVARCHAR(20), + @审核人 NVARCHAR(100) = NULL, + @审核意见 NVARCHAR(1000) = NULL, + @审核完成数量 FLOAT = NULL, + @审核加工开始时间 DATETIME = NULL, + @审核加工完成时间 DATETIME = NULL, + @审核整修开始时间 DATETIME = NULL, + @审核整修结束时间 DATETIME = NULL, + @审核整修方案 NVARCHAR(1000) = NULL +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @审核类型 NVARCHAR(50); + DECLARE @工序流水号 INT; + DECLARE @工作者考勤编号 NVARCHAR(50); + DECLARE @完成数量 FLOAT; + DECLARE @完成类型 INT; + DECLARE @录工票人员编号 INT; + DECLARE @工位号 NVARCHAR(100); + DECLARE @备注 NVARCHAR(500); + DECLARE @设备号 NVARCHAR(100); + DECLARE @整修记录id INT; + DECLARE @整修方案 NVARCHAR(1000); + DECLARE @剩余工时 FLOAT; + DECLARE @剩余数量 INT; + DECLARE @原流程结果 NVARCHAR(100); + DECLARE @完成过程流水号 INT; + DECLARE @是否本过程开启事务 BIT; + DECLARE @原流程返回 TABLE (result NVARCHAR(100)); + + IF NOT EXISTS ( + SELECT 1 + FROM [dbo].[MES_机加工MES_加工完成整修审核表] + WHERE id = @审核流水号 + AND 审核状态 = N'待审核' + ) + BEGIN + SELECT N'0' AS result, N'该审核记录不存在或已审核' AS message; + RETURN; + END; + + IF @审核状态 NOT IN (N'审核通过', N'审核不通过') + BEGIN + SELECT N'0' AS result, N'审核状态不正确' AS message; + RETURN; + END; + + SELECT + @审核类型 = 审核类型, + @工序流水号 = 工序流水号, + @工作者考勤编号 = 工作者考勤编号, + @完成数量 = ISNULL(@审核完成数量, 完成数量), + @完成类型 = 完成类型, + @录工票人员编号 = 录工票人员编号, + @工位号 = 工位号, + @备注 = 备注, + @设备号 = 设备号, + @整修记录id = 整修记录id, + @整修方案 = ISNULL(@审核整修方案, 整修方案) + FROM [dbo].[MES_机加工MES_加工完成整修审核表] + WHERE id = @审核流水号 + AND 审核状态 = N'待审核'; + + BEGIN TRY + SET @是否本过程开启事务 = CASE WHEN @@TRANCOUNT = 0 THEN 1 ELSE 0 END; + IF @是否本过程开启事务 = 1 + BEGIN + BEGIN TRAN; + END + ELSE + BEGIN + SAVE TRAN 生产完成审核保存点; + END; + + IF @审核状态 = N'审核通过' AND @审核类型 = N'加工完成' + BEGIN + IF @工序流水号 IS NULL OR @工作者考勤编号 IS NULL OR @完成数量 IS NULL OR @完成类型 IS NULL OR @录工票人员编号 IS NULL + BEGIN + IF @是否本过程开启事务 = 1 ROLLBACK TRAN ELSE ROLLBACK TRAN 生产完成审核保存点; + SELECT N'0' AS result, N'审核记录缺少原 MES 完工必需参数' AS message; + RETURN; + END; + + IF @完成数量 <= 0 OR @完成数量 <> FLOOR(@完成数量) + BEGIN + IF @是否本过程开启事务 = 1 ROLLBACK TRAN ELSE ROLLBACK TRAN 生产完成审核保存点; + SELECT N'0' AS result, N'完成数量必须为大于 0 的整数' AS message; + RETURN; + END; + + INSERT INTO @原流程返回(result) + EXEC [dbo].[设备管理_零件工序_工序完成过程情况_增加数据] + @工序流水号 = @工序流水号, + @工作者考勤编号 = @工作者考勤编号, + @完成数量 = @完成数量, + @完成类型 = @完成类型, + @录工票人员编号 = @录工票人员编号, + @工位号 = @工位号, + @备注 = @备注, + @剩余工时 = @剩余工时 OUTPUT, + @剩余数量 = @剩余数量 OUTPUT; + + SELECT TOP 1 @原流程结果 = result FROM @原流程返回; + + IF ISNULL(@原流程结果, N'') <> N'成功' + BEGIN + IF @是否本过程开启事务 = 1 ROLLBACK TRAN ELSE ROLLBACK TRAN 生产完成审核保存点; + SELECT N'0' AS result, ISNULL(@原流程结果, N'原 MES 完工流程执行失败') AS message; + RETURN; + END; + + IF @审核加工完成时间 IS NOT NULL + BEGIN + SELECT @完成过程流水号 = MAX(完成过程流水号) + FROM [dbo].[设备管理_零件工序_工序完成过程情况] + WHERE 工序流水号 = @工序流水号 + AND 录工票人员编号 = @录工票人员编号 + AND 完成数量 = @完成数量; + + UPDATE [dbo].[设备管理_零件工序_工序完成过程情况] + SET 加工开始时间 = ISNULL(@审核加工开始时间, 加工开始时间), + 加工完成时间 = @审核加工完成时间, + 完成日期 = CONVERT(DATE, @审核加工完成时间), + 操作日期 = @审核加工完成时间, + 修改人员 = CASE WHEN ISNUMERIC(@审核人) = 1 THEN CAST(@审核人 AS INT) ELSE 修改人员 END, + 修改时间 = GETDATE() + WHERE 完成过程流水号 = @完成过程流水号; + + UPDATE [dbo].[车间生产管理工艺_零件工序] + SET 完成日期 = CASE WHEN 完成日期 IS NULL OR 完成数量 >= ISNULL(完成数量, 0) THEN @审核加工完成时间 ELSE 完成日期 END + WHERE 工序流水号 = @工序流水号; + END; + + IF @审核加工开始时间 IS NOT NULL AND @审核加工完成时间 IS NULL + BEGIN + SELECT @完成过程流水号 = MAX(完成过程流水号) + FROM [dbo].[设备管理_零件工序_工序完成过程情况] + WHERE 工序流水号 = @工序流水号 + AND 录工票人员编号 = @录工票人员编号 + AND 完成数量 = @完成数量; + + UPDATE [dbo].[设备管理_零件工序_工序完成过程情况] + SET 加工开始时间 = @审核加工开始时间, + 修改人员 = CASE WHEN ISNUMERIC(@审核人) = 1 THEN CAST(@审核人 AS INT) ELSE 修改人员 END, + 修改时间 = GETDATE() + WHERE 完成过程流水号 = @完成过程流水号; + END; + END; + + IF @审核状态 = N'审核通过' AND @审核类型 = N'结束整修' + BEGIN + IF @整修记录id IS NULL OR @设备号 IS NULL + BEGIN + IF @是否本过程开启事务 = 1 ROLLBACK TRAN ELSE ROLLBACK TRAN 生产完成审核保存点; + SELECT N'0' AS result, N'审核记录缺少整修结束必需参数' AS message; + RETURN; + END; + + UPDATE [dbo].[设备管理_整修] + SET 整修开始时间 = CASE WHEN @审核整修开始时间 IS NULL THEN 整修开始时间 ELSE CONVERT(VARCHAR(20), @审核整修开始时间, 120) END, + 整修结束时间 = CONVERT(VARCHAR(20), ISNULL(@审核整修结束时间, GETDATE()), 120), + 整修状态 = N'1', + 整修方案 = @整修方案 + WHERE id = @整修记录id + AND 设备号 = @设备号; + END; + + UPDATE [dbo].[MES_机加工MES_加工完成整修审核表] + SET 审核状态 = @审核状态, + 审核人 = @审核人, + 审核时间 = GETDATE(), + 审核意见 = ISNULL(@审核意见, N''), + 完成数量 = CASE WHEN @审核状态 = N'审核通过' AND @审核类型 = N'加工完成' THEN @完成数量 ELSE 完成数量 END, + 开始时间 = CASE + WHEN @审核状态 = N'审核通过' AND @审核类型 = N'加工完成' AND @审核加工开始时间 IS NOT NULL THEN @审核加工开始时间 + WHEN @审核状态 = N'审核通过' AND @审核类型 = N'结束整修' AND @审核整修开始时间 IS NOT NULL THEN @审核整修开始时间 + ELSE 开始时间 + END, + 结束时间 = CASE + WHEN @审核状态 = N'审核通过' AND @审核类型 = N'加工完成' AND @审核加工完成时间 IS NOT NULL THEN @审核加工完成时间 + WHEN @审核状态 = N'审核通过' AND @审核类型 = N'结束整修' THEN ISNULL(@审核整修结束时间, GETDATE()) + ELSE 结束时间 + END, + 整修方案 = CASE WHEN @审核状态 = N'审核通过' AND @审核类型 = N'结束整修' THEN @整修方案 ELSE 整修方案 END, + 剩余工时 = CASE WHEN @审核状态 = N'审核通过' AND @审核类型 = N'加工完成' THEN @剩余工时 ELSE 剩余工时 END, + 剩余数量 = CASE WHEN @审核状态 = N'审核通过' AND @审核类型 = N'加工完成' THEN @剩余数量 ELSE 剩余数量 END, + 修改人 = N'Ld', + 修改时间 = GETDATE() + WHERE id = @审核流水号 + AND 审核状态 = N'待审核'; + + IF @是否本过程开启事务 = 1 + BEGIN + COMMIT TRAN; + END; + END TRY + BEGIN CATCH + IF @@TRANCOUNT > 0 + BEGIN + IF ISNULL(@是否本过程开启事务, 1) = 1 + BEGIN + ROLLBACK TRAN; + END + ELSE + BEGIN + ROLLBACK TRAN 生产完成审核保存点; + END; + END; + + SELECT N'0' AS result, ERROR_MESSAGE() AS message; + RETURN; + END CATCH; + + SELECT N'1' AS result; +END; +GO diff --git a/sql/核心物料搜索栏_物料编码查询_存储过程调整.sql b/sql/核心物料搜索栏_物料编码查询_存储过程调整.sql new file mode 100644 index 00000000..a9792194 --- /dev/null +++ b/sql/核心物料搜索栏_物料编码查询_存储过程调整.sql @@ -0,0 +1,259 @@ +USE [ERPTOOL_JY_20250826Back] +GO + +-- 核心物料搜索栏增加物料编码查询条件 +-- 需求提出人:罗伟 +-- 说明:以下过程补充 @物料编码_check、@物料编码 可选参数。未传入物料编码时保持原查询逻辑不变。 +-- 备注:修改人:Ld 修改时间:2026-06-29 14:30:00 + +ALTER PROCEDURE [dbo].[仓储管理_物料记录_查询新] +@物料名称_check bit = null, +@物料名称 nvarchar(50) = null, +@物料编码_check bit = null, +@物料编码 nvarchar(50) = null, +@时间_check bit = null, +@开始时间 datetime = null, +@结束时间 datetime = null +AS +BEGIN + declare @selectStr nvarchar(4000) + declare @selectStrWhere nvarchar(4000) + + set @selectStr = + 'SELECT row_number() OVER (ORDER BY b.记录时间) AS id, d.*, CONVERT(int, isnull(出库数, 0)) AS 出库数, isnull(入库数, 0) AS 入库数, 库存管理_货位主文件.货位名称, 单位名称_基础表.单位, isnull(库存数, 0) AS 库存数, 记录时间 + FROM (SELECT 物料流水号, 库存数, CONVERT(varchar(10), 操作日期, 23) AS 记录时间 FROM 库存管理_每日库存结余表) AS b + LEFT JOIN (SELECT sum(领料数) AS 出库数, 物料流水号, 领料日期 FROM 仓储管理_出库记录_视图 GROUP BY 物料流水号, 领料日期) AS c ON b.物料流水号 = c.物料流水号 AND c.领料日期 = b.记录时间 + LEFT JOIN (SELECT sum(入库数) AS 入库数, 物料流水号, 入库日期 FROM 仓储管理_入库记录_视图 GROUP BY 物料流水号, 入库日期) AS a ON b.物料流水号 = a.物料流水号 AND a.入库日期 = b.记录时间 + INNER JOIN (SELECT 物料编码, 名称, 代号, 物料流水号, 货位流水号, 单位流水号 FROM 库存管理_物料主文件_基本) AS d ON b.物料流水号 = d.物料流水号 + LEFT JOIN 单位名称_基础表 ON d.单位流水号 = 单位名称_基础表.单位流水号 + LEFT JOIN 库存管理_货位主文件 ON d.货位流水号 = 库存管理_货位主文件.货位流水号 ' + + set @selectStrWhere = ' where 1 = 1 ' + + if(@物料名称_check = 1) + set @selectStrWhere = @selectStrWhere + ' and replace(isnull(名称,''''),'' '','''') + replace(isnull(代号,''''),'' '','''') + replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料名称,'' '','''') + ''%'' ' + + if(@物料编码_check = 1) + set @selectStrWhere = @selectStrWhere + ' and replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料编码,'' '','''') + ''%'' ' + + if(@时间_check = 1) + set @selectStrWhere = @selectStrWhere + ' and 记录时间 >= convert(varchar(10),@开始时间,23) and 记录时间 <= convert(varchar(10),@结束时间,23) ' + + set @selectStr = @selectStr + @selectStrWhere + ' order by 记录时间 desc' + + EXEC sp_executesql @selectStr, + N'@物料名称 nvarchar(50),@物料编码 nvarchar(50),@开始时间 datetime,@结束时间 datetime', + @物料名称,@物料编码,@开始时间,@结束时间 +END +GO + +ALTER PROCEDURE [dbo].[仓储管理_物料记录_查询] +@物料名称_check bit = null, +@物料名称 nvarchar(50) = null, +@物料编码_check bit = null, +@物料编码 nvarchar(50) = null, +@时间_check bit = null, +@开始时间 datetime = null, +@结束时间 datetime = null +AS +BEGIN + declare @selectStr nvarchar(4000) + + set @selectStr = + ' select sum(convert(int,isnull(出库数,0))) as 出库数,sum(isnull(入库数,0)) as 入库数,sum(isnull(库存数,0)) as 库存数 from (select 物料流水号,库存数,convert(varchar(10),操作日期,23) as 记录时间 from 库存管理_每日库存结余表 where 1 = 1 ' + + if(@时间_check = 1) + set @selectStr = @selectStr + ' and convert(varchar(10),操作日期,23) >= @开始时间 and convert(varchar(10),操作日期,23) <= @结束时间 ' + + set @selectStr = @selectStr + + ' ) as b left join (select sum(领料数) as 出库数,物料流水号,领料日期 from 仓储管理_出库记录_视图 where 1=1 ' + + if(@时间_check = 1) + set @selectStr = @selectStr + ' and 领料日期 >= @开始时间 and 领料日期 <= @结束时间 ' + + set @selectStr = @selectStr + + ' group by 物料流水号,领料日期 ) as c on b.物料流水号 = c.物料流水号 and c.领料日期 = b.记录时间 left join (select sum(入库数) as 入库数,物料流水号,入库日期 from 仓储管理_入库记录_视图 where 1=1 ' + + if(@时间_check = 1) + set @selectStr = @selectStr + ' and 入库日期 >= @开始时间 and 入库日期 <= @结束时间 ' + + set @selectStr = @selectStr + + ' group by 物料流水号,入库日期 ) as a on b.物料流水号 = a.物料流水号 and a.入库日期 = b.记录时间 + inner join (select 物料编码,名称,代号,物料流水号,货位流水号,单位流水号 from 库存管理_物料主文件_基本 where 1 = 1 ' + + if(@物料名称_check = 1) + set @selectStr = @selectStr + ' and replace(isnull(名称,''''),'' '','''') + replace(isnull(代号,''''),'' '','''') + replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料名称,'' '','''') + ''%'' ' + + if(@物料编码_check = 1) + set @selectStr = @selectStr + ' and replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料编码,'' '','''') + ''%'' ' + + set @selectStr = @selectStr + + ' ) as d on b.物料流水号 = d.物料流水号 left join 单位名称_基础表 on d.单位流水号 = 单位名称_基础表.单位流水号 + left join 库存管理_货位主文件 on d.货位流水号 = 库存管理_货位主文件.货位流水号 ' + + EXEC sp_executesql @selectStr, + N'@物料名称 nvarchar(50),@物料编码 nvarchar(50),@开始时间 datetime,@结束时间 datetime', + @物料名称,@物料编码,@开始时间,@结束时间 +END +GO + +ALTER PROCEDURE [dbo].[报表_仓储管理_物料记录_查询] +@物料名称_check bit = null, +@物料名称 nvarchar(50) = null, +@物料编码_check bit = null, +@物料编码 nvarchar(50) = null, +@时间_check bit = null, +@开始时间 datetime = null, +@结束时间 datetime = null +AS +BEGIN + select '物料记录_' + replace(replace(replace(CONVERT(nvarchar(19),GETDATE(),21),':',''),'-',''),' ','-') as tablename,'15' as tabletype + select 256*15 as 物料编码,256*30 as 名称,256*30 as 代号,256*10 as 单位,256*15 as 出库数,256*15 as 入库数,256*15 as 库存数,256*15 as 库位,256*15 as 记录日期 + select 0 as 物料编码,0 as 名称,0 as 代号,0 as 单位,1 as 出库数,1 as 入库数,1 as 库存数,0 as 库位,0 as 记录日期 + + declare @selectStr nvarchar(4000) + + set @selectStr = + ' select d.物料编码,名称,代号,单位名称_基础表.单位,isnull(出库数,0) as 出库数,isnull(入库数,0) as 入库数,isnull(库存数,0) as 库存数,库存管理_货位主文件.货位名称 as 库位,记录时间 from (select 物料流水号,库存数,convert(varchar(10),操作日期,23) as 记录时间 from 库存管理_每日库存结余表 where 1 = 1 ' + + if(@时间_check = 1) + set @selectStr = @selectStr + ' and convert(varchar(10),操作日期,23) >= @开始时间 and convert(varchar(10),操作日期,23) <= @结束时间 ' + + set @selectStr = @selectStr + + ' ) as b left join (select sum(领料数) as 出库数,物料流水号,领料日期 from 仓储管理_出库记录_视图 where 1=1 ' + + if(@时间_check = 1) + set @selectStr = @selectStr + ' and 领料日期 >= @开始时间 and 领料日期 <= @结束时间 ' + + set @selectStr = @selectStr + + ' group by 物料流水号,领料日期 ) as c on b.物料流水号 = c.物料流水号 and c.领料日期 = b.记录时间 left join (select sum(入库数) as 入库数,物料流水号,入库日期 from 仓储管理_入库记录_视图 where 1=1 ' + + if(@时间_check = 1) + set @selectStr = @selectStr + ' and 入库日期 >= @开始时间 and 入库日期 <= @结束时间 ' + + set @selectStr = @selectStr + + ' group by 物料流水号,入库日期 ) as a on b.物料流水号 = a.物料流水号 and a.入库日期 = b.记录时间 + inner join (select 物料编码,名称,代号,物料流水号,货位流水号,单位流水号 from 库存管理_物料主文件_基本 where 1 = 1 ' + + if(@物料名称_check = 1) + set @selectStr = @selectStr + ' and replace(isnull(名称,''''),'' '','''') + replace(isnull(代号,''''),'' '','''') + replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料名称,'' '','''') + ''%'' ' + + if(@物料编码_check = 1) + set @selectStr = @selectStr + ' and replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料编码,'' '','''') + ''%'' ' + + set @selectStr = @selectStr + + ' ) as d on b.物料流水号 = d.物料流水号 left join 单位名称_基础表 on d.单位流水号 = 单位名称_基础表.单位流水号 + left join 库存管理_货位主文件 on d.货位流水号 = 库存管理_货位主文件.货位流水号 ' + + EXEC sp_executesql @selectStr, + N'@物料名称 nvarchar(50),@物料编码 nvarchar(50),@开始时间 datetime,@结束时间 datetime', + @物料名称,@物料编码,@开始时间,@结束时间 +END +GO + +ALTER PROCEDURE [dbo].[仓储管理_盘点记录_查询] +@物料名称_check bit = null, +@物料名称 nvarchar(50) = null, +@物料编码_check bit = null, +@物料编码 nvarchar(50) = null, +@时间_check bit = null, +@开始时间 datetime = null, +@结束时间 datetime = null +AS +BEGIN + declare @selectStr nvarchar(4000) + + set @selectStr = ' select * from 库存管理_盘点记录_视图 where 1 = 1 ' + + if(@物料名称_check = 1) + set @selectStr = @selectStr + ' and replace(isnull(名称,''''),'' '','''') + replace(isnull(代号,''''),'' '','''') + replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料名称,'' '','''') + ''%'' ' + + if(@物料编码_check = 1) + set @selectStr = @selectStr + ' and replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料编码,'' '','''') + ''%'' ' + + if(@时间_check = 1) + set @selectStr = @selectStr + ' and convert(varchar(10),修改时间,23) >= @开始时间 and convert(varchar(10),修改时间,23) <= @结束时间 ' + + set @selectStr = @selectStr + ' order by 修改时间 desc ' + + EXEC sp_executesql @selectStr, + N'@物料名称 nvarchar(50),@物料编码 nvarchar(50),@开始时间 datetime,@结束时间 datetime', + @物料名称,@物料编码,@开始时间,@结束时间 +END +GO + +ALTER PROCEDURE [dbo].[报表_仓储管理_盘点记录_查询] +@物料名称_check bit = null, +@物料名称 nvarchar(50) = null, +@物料编码_check bit = null, +@物料编码 nvarchar(50) = null, +@时间_check bit = null, +@开始时间 datetime = null, +@结束时间 datetime = null +AS +BEGIN + select '盘点记录_' + replace(replace(replace(CONVERT(nvarchar(19),GETDATE(),21),':',''),'-',''),' ','-') as tablename,'15' as tabletype + select 256*15 as 物料编码,256*30 as 名称,256*30 as 代号,256*10 as 单位,256*15 as 原库存,256*15 as 盘点后库存,256*15 as 盘点人,256*25 as 盘点时间 + select 0 as 物料编码,0 as 名称,0 as 代号,0 as 单位,1 as 原库存,1 as 盘点后库存,0 as 盘点人,0 as 盘点时间 + + declare @selectStr nvarchar(4000) + + set @selectStr = ' select * from 库存管理_盘点记录_视图 where 1 = 1 ' + + if(@物料名称_check = 1) + set @selectStr = @selectStr + ' and replace(isnull(名称,''''),'' '','''') + replace(isnull(代号,''''),'' '','''') + replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料名称,'' '','''') + ''%'' ' + + if(@物料编码_check = 1) + set @selectStr = @selectStr + ' and replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料编码,'' '','''') + ''%'' ' + + if(@时间_check = 1) + set @selectStr = @selectStr + ' and convert(varchar(10),修改时间,23) >= @开始时间 and convert(varchar(10),修改时间,23) <= @结束时间 ' + + EXEC sp_executesql @selectStr, + N'@物料名称 nvarchar(50),@物料编码 nvarchar(50),@开始时间 datetime,@结束时间 datetime', + @物料名称,@物料编码,@开始时间,@结束时间 +END +GO + +ALTER PROCEDURE [dbo].[仓储管理_入库记录退货_条件查询] +@物料名称_check bit = null, +@物料名称 nvarchar(50) = null, +@采购合同_check bit = null, +@采购合同 nvarchar(50) = null, +@供应商_check bit = null, +@供应商 nvarchar(50) = null, +@物料编码_check bit = null, +@物料编码 nvarchar(50) = null, +@时间_check bit = null, +@开始时间 nvarchar(50) = null, +@结束时间 nvarchar(50) = null +AS +BEGIN + declare @selectStr nvarchar(4000) + declare @selectStrWhere nvarchar(4000) + + set @selectStr = ' select * from [dbo].[仓储管理_入库记录退货_视图] ' + set @selectStrWhere = ' where 1 = 1 ' + + if(@物料名称_check = 1) + set @selectStrWhere = @selectStrWhere + ' and 物料名称 + 图号或型号 like ''%'' + @物料名称 + ''%'' ' + + if(@采购合同_check = 1) + set @selectStrWhere = @selectStrWhere + ' and 采购合同 like ''%'' + @采购合同 + ''%'' ' + + if(@供应商_check = 1) + set @selectStrWhere = @selectStrWhere + ' and 供应商 like ''%'' + @供应商 + ''%'' ' + + if(@物料编码_check = 1) + set @selectStrWhere = @selectStrWhere + ' and replace(isnull(物料编码,''''),'' '','''') like ''%'' + replace(@物料编码,'' '','''') + ''%'' ' + + if(@时间_check = 1) + set @selectStrWhere = @selectStrWhere + ' and convert(varchar(10),退货时间,23) >= @开始时间 and convert(varchar(10),退货时间,23) <= @结束时间 ' + + set @selectStr = @selectStr + @selectStrWhere + ' order by 退货时间 desc ' + + EXEC sp_executesql @selectStr, + N'@物料名称 nvarchar(50),@采购合同 nvarchar(50),@供应商 nvarchar(50),@物料编码 nvarchar(50),@开始时间 nvarchar(50),@结束时间 nvarchar(50)', + @物料名称,@采购合同,@供应商,@物料编码,@开始时间,@结束时间 +END +GO diff --git a/sql/生产审核菜单组件路径修正.sql b/sql/生产审核菜单组件路径修正.sql new file mode 100644 index 00000000..6b7fd170 --- /dev/null +++ b/sql/生产审核菜单组件路径修正.sql @@ -0,0 +1,11 @@ +-- 修正生产审核菜单组件路径,避免动态路由加载不存在的 ProductionCompletionAudi 目录 修改人:Ld 修改时间:2026-07-02 14:12:00; +UPDATE dbo.基础表_模块信息 +SET path = N'SeikoWorkshop/ProductionCompletionAudit', + component = N'/SeikoWorkshop/ProductionCompletionAudit', + name = N'ProductionCompletionAudit' +WHERE id = 152 + AND title = N'生产审核'; + +SELECT id, path, component, name, title +FROM dbo.基础表_模块信息 +WHERE id = 152; diff --git a/sql/采购入库合同明细_关联未入库最新到货.sql b/sql/采购入库合同明细_关联未入库最新到货.sql new file mode 100644 index 00000000..1be291be --- /dev/null +++ b/sql/采购入库合同明细_关联未入库最新到货.sql @@ -0,0 +1,50 @@ +-- 采购入库合同明细关联未入库最新到货记录 +-- 修改人:Ld 修改时间:2026-07-02 17:11:48; + +ALTER VIEW dbo.采购管理_采购合同明细_视图 +AS +SELECT dbo.采购管理_采购合同明细.采购合同明细流水号, dbo.库存管理_物料主文件_基本.名称 AS 物料名称, + dbo.库存管理_物料主文件_基本.代号 AS 图号或型号, dbo.采购管理_采购合同明细.单位, CASE WHEN isnull(是否主轴, + 0) = 1 THEN 采购管理_采购批次.数量 ELSE 采购管理_采购合同明细.数量 END AS 采购数, CASE WHEN isnull(是否主轴, + 0) = 1 THEN 采购管理_采购批次.已到数 ELSE 已到货数量 END AS 已到数, + dbo.合同管理_订单信息_基础表.订单编号 AS 订单号, dbo.合同管理_订单信息_基础表.订单流水号, + dbo.采购管理_采购合同明细.采购合同流水号, dbo.采购管理_采购合同明细.标准件和外购件流水号, + dbo.PDM_零件明细表_标准件和外购件.组件流水号, dbo.采购管理_采购合同.供应商流水号, + dbo.PDM_零件明细表_标准件和外购件.物料流水号, dbo.采购管理_合同审批.审批情况流水号, + ISNULL(dbo.库存管理_物料主文件_基本.货位流水号, 0) AS 货位流水号, dbo.库存管理_货位主文件.货位名称, + dbo.采购管理_采购批次.批号, dbo.采购管理_采购批次.是否主轴, dbo.采购管理_采购合同明细.备注, + dbo.PDM_零件明细表_标准件和外购件.是否使用库存, dbo.库存管理_物料主文件_基本.物料编码, + dbo.采购管理_手动完成记录.id AS 手动完成id, 到货最新.到货数 AS 采购到货数, + dbo.采购管理_采购合同.采购合同编号 AS 合同号, dbo.采购管理_供应商.供应商名称, 到货最新.已检数量, + 到货最新.等待入库数量 +FROM dbo.采购管理_采购合同明细 INNER JOIN + dbo.PDM_零件明细表_标准件和外购件 ON + dbo.采购管理_采购合同明细.标准件和外购件流水号 = dbo.PDM_零件明细表_标准件和外购件.标准件和外购件流水号 INNER + JOIN + dbo.库存管理_物料主文件_基本 ON + dbo.PDM_零件明细表_标准件和外购件.物料流水号 = dbo.库存管理_物料主文件_基本.物料流水号 INNER JOIN + dbo.PDM_组件名称 ON + dbo.PDM_零件明细表_标准件和外购件.组件流水号 = dbo.PDM_组件名称.组件流水号 INNER JOIN + dbo.PDM_机床名称 ON dbo.PDM_组件名称.机床流水号 = dbo.PDM_机床名称.机床流水号 INNER JOIN + dbo.PDM_项目名称 ON dbo.PDM_机床名称.项目流水号 = dbo.PDM_项目名称.项目流水号 INNER JOIN + dbo.合同管理_订单信息_基础表 ON + dbo.PDM_项目名称.项目流水号 = dbo.合同管理_订单信息_基础表.项目流水号 INNER JOIN + dbo.采购管理_采购合同 ON + dbo.采购管理_采购合同明细.采购合同流水号 = dbo.采购管理_采购合同.采购合同流水号 INNER JOIN + dbo.采购管理_采购批次 ON + dbo.采购管理_采购合同明细.采购合同明细流水号 = dbo.采购管理_采购批次.采购合同明细流水号 INNER JOIN + dbo.采购管理_供应商 ON + dbo.采购管理_采购合同.供应商流水号 = dbo.采购管理_供应商.供应商流水号 OUTER APPLY + (SELECT TOP 1 * + FROM dbo.采购管理_采购到货 + WHERE 采购合同流水号 = dbo.采购管理_采购合同明细.采购合同流水号 + AND 物料流水号 = dbo.库存管理_物料主文件_基本.物料流水号 + AND ISNULL(质检状态, '') <> N'已入库' + ORDER BY ISNULL(id, 0) DESC) AS 到货最新 LEFT OUTER JOIN + dbo.库存管理_货位主文件 ON + dbo.库存管理_物料主文件_基本.货位流水号 = dbo.库存管理_货位主文件.货位流水号 LEFT OUTER JOIN + dbo.采购管理_合同审批 ON + dbo.采购管理_采购合同.采购合同流水号 = dbo.采购管理_合同审批.采购合同流水号 LEFT OUTER JOIN + dbo.采购管理_手动完成记录 ON + dbo.采购管理_采购合同明细.采购合同明细流水号 = dbo.采购管理_手动完成记录.采购合同明细流水号 +GO diff --git a/sql/零件改制_发起改制_精确基本件.sql b/sql/零件改制_发起改制_精确基本件.sql new file mode 100644 index 00000000..07a06d28 --- /dev/null +++ b/sql/零件改制_发起改制_精确基本件.sql @@ -0,0 +1,315 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +ALTER PROCEDURE [dbo].[技术中心_改制订单_发起改制] + @原订单流水号 int = null, + @原组件流水号 int = null, + @改制零件名称 nvarchar(50) = null, + @改制零件图号 nvarchar(50) = null, + @改制数量 int = null, + @精工期限 date = null, + @发起人 int = null, + @原零件名称 nvarchar(50) = null, + @原零件图号 nvarchar(50) = null, + @原基本件流水号 int = null +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @工艺计划流水号 int; + DECLARE @改制订单流水号 int; + DECLARE @改制订单编号 varchar(100); + DECLARE @改制工艺编号 int; + DECLARE @工序流水号 int; + DECLARE @改制物料流水号 int; + + DECLARE @单号排序代码 varchar(100); + DECLARE @年份 varchar(100); + DECLARE @n int; + + IF ISNULL(LTRIM(RTRIM(@原零件图号)), '') <> '' + AND ISNULL(LTRIM(RTRIM(@改制零件图号)), '') <> '' + AND LTRIM(RTRIM(@原零件图号)) = LTRIM(RTRIM(@改制零件图号)) + BEGIN + SELECT '0' AS result, '改制零件图号不能与原零件图号相同' AS msg; + RETURN; + END; + + IF @原订单流水号 IS NULL OR @原组件流水号 IS NULL + BEGIN + SELECT '0' AS result, '原订单流水号或原组件流水号不能为空' AS msg; + RETURN; + END; + + IF ISNULL(@改制零件名称, '') = '' OR ISNULL(@改制零件图号, '') = '' + BEGIN + SELECT '0' AS result, '改制零件名称或改制零件图号不能为空' AS msg; + RETURN; + END; + + IF ISNULL(@改制数量, 0) <= 0 + BEGIN + SELECT '0' AS result, '改制数量必须大于0' AS msg; + RETURN; + END; + + -- 修改人:Ld 修改时间:2026-07-01 14:45:00; 优先使用前端点击行传入的原基本件流水号,避免同组件内重复零件或历史流水号导致改制记录回显错位。 + IF @原基本件流水号 IS NULL + BEGIN + SELECT TOP 1 + @原基本件流水号 = B.流水号 + FROM dbo.PDM_零件明细表_所有视图 AS B + WHERE B.订单流水号 = @原订单流水号 + AND B.组件流水号 = @原组件流水号 + AND (ISNULL(@原零件名称, '') = '' OR B.零件名称 = @原零件名称) + AND (ISNULL(@原零件图号, '') = '' OR B.[图号或型号] = @原零件图号) + ORDER BY B.流水号 DESC; + END; + + IF @原基本件流水号 IS NULL + BEGIN + SELECT TOP 1 + @原基本件流水号 = 基本件流水号 + FROM dbo.PDM_零件明细表_基本件 + WHERE 组件流水号 = @原组件流水号 + ORDER BY 基本件流水号 DESC; + END; + + IF @原基本件流水号 IS NULL + BEGIN + SELECT '0' AS result, '未找到原零件基本件流水号' AS msg; + RETURN; + END; + + SELECT TOP 1 + @改制物料流水号 = 物料流水号 + FROM dbo.库存管理_物料主文件_基本 + WHERE LTRIM(RTRIM(名称)) = LTRIM(RTRIM(@改制零件名称)) + AND LTRIM(RTRIM(代号)) = LTRIM(RTRIM(@改制零件图号)) + AND ISNULL(是否禁用, 0) = 0 + ORDER BY 物料流水号 DESC; + + IF @改制物料流水号 IS NULL + BEGIN + SELECT '0' AS result, '未找到改制零件对应的新物料,请先维护物料信息' AS msg; + RETURN; + END; + + IF @精工期限 IS NULL + SET @精工期限 = CONVERT(date, GETDATE()); + + BEGIN TRY + BEGIN TRAN; + + SELECT @n = COUNT(*) + FROM dbo.技术中心_改制订单排序 + WHERE 年份 = CONVERT(varchar(4), GETDATE(), 23); + + IF @n = 0 + BEGIN + SET @年份 = CONVERT(varchar(4), GETDATE(), 23); + + INSERT INTO dbo.技术中心_改制订单排序(年份, 数量) + VALUES(@年份, 1); + + SET @单号排序代码 = 1; + END + ELSE + BEGIN + UPDATE dbo.技术中心_改制订单排序 + SET 数量 = 数量 + 1 + WHERE 年份 = CONVERT(varchar(4), GETDATE(), 23); + + SELECT @单号排序代码 = 数量 + FROM dbo.技术中心_改制订单排序 + WHERE 年份 = CONVERT(varchar(4), GETDATE(), 23); + END; + + SET @单号排序代码 = RIGHT(10000 + CONVERT(varchar(100), @单号排序代码), 4); + + SET @改制订单编号 = + 'BHGZ' + '-' + + DATENAME(year, GETDATE()) + + DATENAME(month, GETDATE()) + + RIGHT(100 + DAY(GETDATE()), 2) + + CONVERT(varchar, @单号排序代码); + + INSERT INTO dbo.技术中心_改制订单记录 + ( + 改制订单编号, + 原订单流水号, + 原组件流水号, + 原基本件流水号, + 原零件名称, + 原零件图号, + 改制零件名称, + 改制零件图号, + 改制物料流水号, + 改制数量, + 精工期限, + 状态, + 发起人, + 发起时间, + 是否删除 + ) + VALUES + ( + @改制订单编号, + @原订单流水号, + @原组件流水号, + @原基本件流水号, + @原零件名称, + @原零件图号, + @改制零件名称, + @改制零件图号, + @改制物料流水号, + @改制数量, + @精工期限, + N'待生成任务', + @发起人, + GETDATE(), + 0 + ); + + SET @改制订单流水号 = SCOPE_IDENTITY(); + + INSERT INTO dbo.车间生产管理工艺_零件工艺计划 + ( + 基本件流水号, + 零件图号, + 批次数量, + 操作日期, + 考核状态, + 工艺更新时间, + 工艺员编号, + 计划完成 + ) + VALUES + ( + @原基本件流水号, + @改制零件图号, + @改制数量, + GETDATE(), + 2, + GETDATE(), + @发起人, + @精工期限 + ); + + SET @工艺计划流水号 = SCOPE_IDENTITY(); + + UPDATE dbo.技术中心_改制订单记录 + SET 工艺计划流水号 = @工艺计划流水号, + 状态 = N'工艺完成' + WHERE 改制订单流水号 = @改制订单流水号; + + SELECT TOP 1 + @改制工艺编号 = 工艺编号 + FROM dbo.车间生产管理工艺_基础表_工艺名称 + WHERE 工艺名称 = N'改制' + AND ISNULL(是否启用, 1) = 1; + + IF @改制工艺编号 IS NULL + BEGIN + INSERT INTO dbo.车间生产管理工艺_基础表_工艺名称(工艺名称, 是否启用) + VALUES(N'改制', 1); + + SET @改制工艺编号 = SCOPE_IDENTITY(); + END; + + SELECT TOP 1 + @工序流水号 = 工序流水号 + FROM dbo.车间生产管理工艺_零件工序 + WHERE 工艺计划流水号 = @工艺计划流水号 + ORDER BY 工序顺序; + + IF @工序流水号 IS NOT NULL + BEGIN + UPDATE dbo.车间生产管理工艺_零件工序 + SET 工艺编号 = @改制工艺编号, + 工序顺序 = 1, + 工艺要求 = N'改制', + 工序间是否外协 = 0, + 外协数量 = 0, + 是否最后一序 = 1, + 定额工时 = 0, + 准结工时 = 0, + 已分配数 = 0, + 已外协数 = 0, + 是否允许变更 = 1 + WHERE 工序流水号 = @工序流水号; + END + ELSE + BEGIN + INSERT INTO dbo.车间生产管理工艺_零件工序 + ( + 工艺计划流水号, + 工艺编号, + 工序顺序, + 工艺要求, + 工序间是否外协, + 外协数量, + 是否最后一序, + 定额工时, + 准结工时, + 已分配数, + 已外协数, + 是否允许变更 + ) + VALUES + ( + @工艺计划流水号, + @改制工艺编号, + 1, + N'改制', + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ); + END; + + EXEC dbo.精工车间_工艺保存_派工 + @工艺计划流水号 = @工艺计划流水号, + @人员编号 = @发起人; + + UPDATE dbo.PDM_组件名称 + SET 组件精工车间 = 1, + 是否分配 = 1 + WHERE 组件流水号 = @原组件流水号; + + UPDATE dbo.合同管理_订单信息_基础表 + SET 精工车间 = 1, + 是否下达 = 1, + 技术审核 = 0, + 下达人 = @发起人, + 下达日期 = GETDATE(), + 精工期限 = @精工期限 + WHERE 订单流水号 = @原订单流水号; + + COMMIT TRAN; + + SELECT + '1' AS result, + '改制订单已生成' AS msg, + @改制订单流水号 AS 改制订单流水号, + @改制订单编号 AS 改制订单编号, + @工艺计划流水号 AS 工艺计划流水号, + @改制物料流水号 AS 改制物料流水号; + END TRY + BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK TRAN; + + SELECT + '0' AS result, + ERROR_MESSAGE() AS msg; + END CATCH; +END; +GO diff --git a/src/views/AssemblyManagement/ReceiveAssemblyTask/index.vue b/src/views/AssemblyManagement/ReceiveAssemblyTask/index.vue index cbb471f4..3fc4587d 100644 --- a/src/views/AssemblyManagement/ReceiveAssemblyTask/index.vue +++ b/src/views/AssemblyManagement/ReceiveAssemblyTask/index.vue @@ -63,7 +63,7 @@ 接收任务 - 打回 + 打回 历史订单 查看订单 diff --git a/src/views/SeikoWorkshop/ProcessPrice/index.vue b/src/views/SeikoWorkshop/ProcessPrice/index.vue new file mode 100644 index 00000000..8e096615 --- /dev/null +++ b/src/views/SeikoWorkshop/ProcessPrice/index.vue @@ -0,0 +1,774 @@ + + + + + diff --git a/src/views/SeikoWorkshop/ProductionCompletionAudit/index.vue b/src/views/SeikoWorkshop/ProductionCompletionAudit/index.vue new file mode 100644 index 00000000..89e79182 --- /dev/null +++ b/src/views/SeikoWorkshop/ProductionCompletionAudit/index.vue @@ -0,0 +1,457 @@ + + + + + + diff --git a/src/views/SeikoWorkshop/WorkingHoursStatistics/index.vue b/src/views/SeikoWorkshop/WorkingHoursStatistics/index.vue index a438ba97..ca11670f 100644 --- a/src/views/SeikoWorkshop/WorkingHoursStatistics/index.vue +++ b/src/views/SeikoWorkshop/WorkingHoursStatistics/index.vue @@ -20,7 +20,8 @@ @change="searchTable"/> 导出 - + +

@@ -50,12 +51,18 @@ {{ scope.row.加工工时 }} + + + +
- +
@@ -102,6 +109,17 @@ {{ scope.row.完成数 }} + + + + + + + + + + +
- +
@@ -243,6 +268,17 @@ {{ scope.row.完成数 }} + + + + + + +