Merge branch '20260519-3.9.2版本-葛昊天分支'
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -4,6 +4,8 @@
|
|||||||
"java.import.maven.enabled": true,
|
"java.import.maven.enabled": true,
|
||||||
"java.configuration.updateBuildConfiguration": "automatic",
|
"java.configuration.updateBuildConfiguration": "automatic",
|
||||||
"java.autobuild.enabled": true,
|
"java.autobuild.enabled": true,
|
||||||
|
"java.import.maven.offline.enabled": false,
|
||||||
|
"java.configuration.maven.notCoveredPluginExecutionSeverity": "ignore",
|
||||||
"java.jdt.ls.java.home": "C:\\Program Files\\Java\\jdk-17",
|
"java.jdt.ls.java.home": "C:\\Program Files\\Java\\jdk-17",
|
||||||
"java.configuration.runtimes": [
|
"java.configuration.runtimes": [
|
||||||
{
|
{
|
||||||
|
|||||||
2
jeecg-boot/.vscode/settings.json
vendored
2
jeecg-boot/.vscode/settings.json
vendored
@@ -4,6 +4,8 @@
|
|||||||
"java.import.maven.enabled": true,
|
"java.import.maven.enabled": true,
|
||||||
"java.configuration.updateBuildConfiguration": "automatic",
|
"java.configuration.updateBuildConfiguration": "automatic",
|
||||||
"java.autobuild.enabled": true,
|
"java.autobuild.enabled": true,
|
||||||
|
"java.import.maven.offline.enabled": false,
|
||||||
|
"java.configuration.maven.notCoveredPluginExecutionSeverity": "ignore",
|
||||||
"java.jdt.ls.java.home": "C:\\Program Files\\Java\\jdk-17",
|
"java.jdt.ls.java.home": "C:\\Program Files\\Java\\jdk-17",
|
||||||
"java.configuration.runtimes": [
|
"java.configuration.runtimes": [
|
||||||
{
|
{
|
||||||
|
|||||||
18
jeecg-boot/.vscode/tasks.json
vendored
Normal file
18
jeecg-boot/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Maven: 修复 Java Classpath",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "mvn clean install -DskipTests -pl jeecg-boot-base-core,jeecg-boot-module/jeecg-module-print,jeecg-boot-module/jeecg-module-xslmes -am",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": false
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -104,6 +104,234 @@ jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecMo
|
|||||||
-- author:cursor---date:20260521--for: 【配合示方】编辑打开时基本资料闪清修复 ---
|
-- author:cursor---date:20260521--for: 【配合示方】编辑打开时基本资料闪清修复 ---
|
||||||
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue
|
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【配合示方】状态字典调整为审批流程8项 ---
|
||||||
|
jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_97__mes_xsl_formula_spec_status_dict.sql
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【配合示方】密炼PS校对/审核/批准联动同步状态与审批人 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerPsCompileServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A17】新增MES技术管理-混炼示方1主4子表及紧凑页 ---
|
||||||
|
jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_98__mes_xsl_mixing_spec.sql
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpec.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecMaterial.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecStep.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecDownStep.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecTcu.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslMixingSpecPage.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMapper.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecMaterialMapper.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecStepMapper.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecDownStepMapper.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixingSpecTcuMapper.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixingSpecService.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpecList.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A33】新增混炼示方主表/明细字段交互优化 ---
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixerAction/components/MesXslMixerActionSelectModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixerCondition/components/MesXslMixerConditionSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A34】混炼示方动作/组合改为下拉选择 ---
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A35】混炼示方动作/组合列常显下拉倒三角 ---
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingStepSelectCell.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】F段明细加入最后一段B炼好胶(如三段用B2)+Q列配合剂 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】B2/Bn明细改为上一段胶料一条(B{n-1}+胶料名)+本段列配合剂 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】修复B2与B1相同:按列增量拼接并支持列2+非Q配合剂 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerateRowVO.java
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaGenerateMixingModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】生成混炼示方B段改为Bn=B(n-1)+第n列有值配合剂增量拼接 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】生成混炼示方明细种类按分类字典is_rubber显示胶料或小类名 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】生成混炼示方编号原样追加胶料代号中胶料名称后的后缀 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】生成混炼示方明细按STEP过滤:B段仅A物料、F段仅Q物料 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A38】配合示方生成混炼示方(预览段×机台批量创建) ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslFormulaMixingGenerate*.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslFormulaSpecService.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslFormulaSpecController.java
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpecList.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaSpecModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/components/MesXslFormulaGenerateMixingModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A36】混炼示方动作/组合下拉列表被表格裁切修复 ---
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingStepSelectCell.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A43】混炼示方换算系数联动橡胶及配合剂单重实时计算 ---
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A42】混炼示方橡胶及配合剂明细底部固定合计行 ---
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A41】混炼示方橡胶及配合剂明细累计按种类分组合计 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A44】配合示方生成混炼示方时按设备台账有效体积自动计算填充体积 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A45】混炼示方保存/批量生成子表改批量插入并延长前端超时 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.api.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslFormulaSpec/MesXslFormulaSpec.api.ts
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A46】混炼示方换算系数/单重/机台有效体积联动填充体积 ---
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A47】混炼示方保存分步骤性能诊断日志 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixingSpecController.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A48】生成混炼示方时同步B/F段胶至密炼物料(母炼胶/A胶、终炼胶/Q胶) ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料 ---
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】MES物料小类胶料标记/生成混炼示方种类映射/混炼示方选料弹窗 ---
|
||||||
|
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
jeecgboot-vue3/src/views/system/category/category.constants.ts
|
||||||
|
jeecgboot-vue3/src/views/system/category/category.data.ts
|
||||||
|
jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue
|
||||||
|
jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗左侧小类树为空修复(对齐密炼物料列表树加载/异步展开/隐藏配置重置) ---
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗小类设置无明细/统一分类加载函数 -----------
|
||||||
|
jeecgboot-vue3/src/views/system/category/category.constants.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗分类加载改为getChildListBatch两级查询 -----------
|
||||||
|
jeecgboot-vue3/src/views/system/category/category.constants.ts
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗openModal未传data导致初始化未执行 -----------
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗移出父Modal+useModalInner初始化 -----------
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】小类展示分组勾选互不覆盖 -----------
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A50】选料弹窗隐藏ERP列并新增自动/人工称量列 -----------
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A51】密炼物料种类配置表及列表批量新增 -----------
|
||||||
|
jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_102__mes_xsl_mixer_material_kind_cfg.sql
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixerMaterialKindCfg.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslMixerMaterialKindCfgMapper.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerMaterialKindCfgService.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerMaterialKindCfgServiceImpl.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerMaterialKindCfgController.java
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.api.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgBatchModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/components/MesXslMixerMaterialKindCfgEditModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A51】密炼物料种类配置菜单ID冲突修复 -----------
|
||||||
|
jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_102__mes_xsl_mixer_material_kind_cfg.sql
|
||||||
|
jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_103__mes_xsl_mixer_material_kind_cfg_menu_fix.sql
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】混炼示方种类改读密炼物料种类配置(生成/选料弹窗) -----------
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslMixerMaterialKindLookupVO.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerMaterialKindCfgService.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerMaterialKindCfgServiceImpl.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerMaterialKindCfgController.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfg.api.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】选料弹窗层级修复及关闭父弹窗时同步关闭 -----------
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】选料弹窗左侧物料小类树会话缓存 -----------
|
||||||
|
jeecgboot-vue3/src/views/system/category/category.constants.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】选料弹窗小类设置按钮 Popover 层级修复 -----------
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】选料弹窗小类设置新增刷新分类字典 -----------
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialCategorySetting.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A52】高层级弹窗内 Message 提示层级修复 -----------
|
||||||
|
jeecgboot-vue3/src/design/public.less
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A53】种类解析移除小类名兜底/通用选料弹窗接配置/配置变更清缓存 -----------
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerMaterialKindCfgService.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerMaterialKindCfgServiceImpl.java
|
||||||
|
jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSelectModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingMaterialSelectModal.vue
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList.vue
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A54】母炼胶明细行绑定已同步密炼物料主数据及种类配置解析 -----------
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A55】混炼示方明细新增密炼物料ID字段 -----------
|
||||||
|
jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_104__mes_xsl_mixing_spec_material_mixer_material_id.sql
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecMaterial.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslFormulaSpecServiceImpl.java
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data.ts
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A56】混炼示方批量删除性能优化(子表批量删+去重同步删密炼物料) -----------
|
||||||
|
jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||||
|
|
||||||
|
-- author:cursor---date:20260525--for: 【XSLMES-20260525-A57】混合步骤动作/组合下拉最多展示20条 -----------
|
||||||
|
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingStepSelectCell.vue
|
||||||
|
|
||||||
-- author:jiangxh---date:20260522--for: 【MES】胶料快检实验类型:质量管理目录、001自动编号、CRUD与菜单权限 ---
|
-- author:jiangxh---date:20260522--for: 【MES】胶料快检实验类型:质量管理目录、001自动编号、CRUD与菜单权限 ---
|
||||||
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_97__mes_xsl_rubber_quick_test_type.sql
|
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_97__mes_xsl_rubber_quick_test_type.sql
|
||||||
jeecg-boot/db/mes-xsl-rubber-quick-test-type-menu-permission.sql
|
jeecg-boot/db/mes-xsl-rubber-quick-test-type-menu-permission.sql
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
<groupId>org.jeecgframework.boot3</groupId>
|
||||||
<artifactId>jeecg-boot-base-core</artifactId>
|
<artifactId>jeecg-boot-base-core</artifactId>
|
||||||
|
<version>${jeecgboot.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- 复用打印模板模块:打印机枚举、业务绑定、PDF 提交队列 -->
|
<!-- 复用打印模板模块:打印机枚举、业务绑定、PDF 提交队列 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec;
|
|||||||
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine;
|
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService;
|
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService;
|
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewVO;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRequestVO;
|
||||||
import org.jeecg.modules.xslmes.vo.MesXslFormulaRubberContentSettingVO;
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaRubberContentSettingVO;
|
||||||
import org.jeecg.modules.xslmes.vo.MesXslFormulaSpecPage;
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaSpecPage;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
@@ -173,6 +175,32 @@ public class MesXslFormulaSpecController extends JeecgController<MesXslFormulaSp
|
|||||||
}
|
}
|
||||||
//update-end---author:cursor ---date:20260521 for:【配合示方】含胶率物料小类可配置-----------
|
//update-end---author:cursor ---date:20260521 for:【配合示方】含胶率物料小类可配置-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方-----------
|
||||||
|
@Operation(summary = "MES配合示方-生成混炼示方预览")
|
||||||
|
@GetMapping(value = "/buildMixingGeneratePreview")
|
||||||
|
public Result<MesXslFormulaMixingGeneratePreviewVO> buildMixingGeneratePreview(
|
||||||
|
@RequestParam(name = "formulaSpecId", required = true) String formulaSpecId) {
|
||||||
|
try {
|
||||||
|
return Result.OK(mesXslFormulaSpecService.buildMixingGeneratePreview(formulaSpecId));
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
return Result.error(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "MES配合示方-生成混炼示方")
|
||||||
|
@Operation(summary = "MES配合示方-生成混炼示方")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:add")
|
||||||
|
@PostMapping(value = "/generateMixingSpec")
|
||||||
|
public Result<Map<String, Object>> generateMixingSpec(@RequestBody MesXslFormulaMixingGenerateRequestVO request) {
|
||||||
|
try {
|
||||||
|
int count = mesXslFormulaSpecService.generateMixingSpecFromFormula(request);
|
||||||
|
return Result.OK("成功生成 " + count + " 条混炼示方", Map.of("count", count));
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
return Result.error(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方-----------
|
||||||
|
|
||||||
@RequiresPermissions("xslmes:mes_xsl_formula_spec:exportXls")
|
@RequiresPermissions("xslmes:mes_xsl_formula_spec:exportXls")
|
||||||
@RequestMapping(value = "/exportXls")
|
@RequestMapping(value = "/exportXls")
|
||||||
public ModelAndView exportXls(HttpServletRequest request, MesXslFormulaSpec model) {
|
public ModelAndView exportXls(HttpServletRequest request, MesXslFormulaSpec model) {
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
package org.jeecg.modules.xslmes.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslMixerMaterialKindCfgService;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslMixerMaterialKindLookupVO;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES 密炼物料种类配置
|
||||||
|
*/
|
||||||
|
@Tag(name = "MES密炼物料种类配置")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/xslmes/mesXslMixerMaterialKindCfg")
|
||||||
|
@Slf4j
|
||||||
|
public class MesXslMixerMaterialKindCfgController
|
||||||
|
extends JeecgController<MesXslMixerMaterialKindCfg, IMesXslMixerMaterialKindCfgService> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslMixerMaterialKindCfgService mesXslMixerMaterialKindCfgService;
|
||||||
|
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-分页列表查询")
|
||||||
|
@GetMapping(value = "/list")
|
||||||
|
public Result<IPage<MesXslMixerMaterialKindCfg>> queryPageList(
|
||||||
|
MesXslMixerMaterialKindCfg model,
|
||||||
|
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||||
|
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||||
|
HttpServletRequest req) {
|
||||||
|
QueryWrapper<MesXslMixerMaterialKindCfg> queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
|
||||||
|
queryWrapper.orderByAsc("priority").orderByDesc("create_time");
|
||||||
|
Page<MesXslMixerMaterialKindCfg> page = new Page<>(pageNo, pageSize);
|
||||||
|
IPage<MesXslMixerMaterialKindCfg> pageList = mesXslMixerMaterialKindCfgService.page(page, queryWrapper);
|
||||||
|
return Result.OK(pageList);
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存-----------
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-按根字典/分类展开明细")
|
||||||
|
@GetMapping(value = "/expandLines")
|
||||||
|
public Result<List<MesXslMixerMaterialKindCfg>> expandLines(
|
||||||
|
@RequestParam(name = "sourceType") String sourceType,
|
||||||
|
@RequestParam(name = "sourceRootCode") String sourceRootCode,
|
||||||
|
@RequestParam(name = "tenantId", required = false) Integer tenantId) {
|
||||||
|
List<MesXslMixerMaterialKindCfg> lines =
|
||||||
|
mesXslMixerMaterialKindCfgService.expandLines(sourceType, sourceRootCode, tenantId);
|
||||||
|
return Result.OK(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "MES密炼物料种类配置-批量添加")
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-批量添加")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:add")
|
||||||
|
@PostMapping(value = "/addBatch")
|
||||||
|
public Result<String> addBatch(@RequestBody List<MesXslMixerMaterialKindCfg> lines) {
|
||||||
|
mesXslMixerMaterialKindCfgService.saveBatchLines(lines, null);
|
||||||
|
return Result.OK("添加成功!");
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-加载种类查找表")
|
||||||
|
@GetMapping(value = "/kindLookup")
|
||||||
|
public Result<MesXslMixerMaterialKindLookupVO> kindLookup(
|
||||||
|
@RequestParam(name = "tenantId", required = false) Integer tenantId) {
|
||||||
|
return Result.OK(mesXslMixerMaterialKindCfgService.loadKindLookup(tenantId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-解析混炼示方明细种类")
|
||||||
|
@GetMapping(value = "/resolveKind")
|
||||||
|
public Result<String> resolveKind(
|
||||||
|
@RequestParam(name = "minorCategoryId", required = false) String minorCategoryId,
|
||||||
|
@RequestParam(name = "weighMode", required = false) String weighMode,
|
||||||
|
@RequestParam(name = "minorCategoryName", required = false) String minorCategoryName,
|
||||||
|
@RequestParam(name = "tenantId", required = false) Integer tenantId) {
|
||||||
|
MesXslMixerMaterialKindLookupVO lookup = mesXslMixerMaterialKindCfgService.loadKindLookup(tenantId);
|
||||||
|
String kind = mesXslMixerMaterialKindCfgService.resolveMixingMaterialKind(
|
||||||
|
lookup, minorCategoryId, weighMode, minorCategoryName);
|
||||||
|
return Result.OK(kind);
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||||
|
|
||||||
|
@AutoLog(value = "MES密炼物料种类配置-添加")
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-添加")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:add")
|
||||||
|
@PostMapping(value = "/add")
|
||||||
|
public Result<String> add(@RequestBody MesXslMixerMaterialKindCfg model) {
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验-----------
|
||||||
|
String err = validateForSave(model, false);
|
||||||
|
if (err != null) {
|
||||||
|
return Result.error(err);
|
||||||
|
}
|
||||||
|
model.setDelFlag(CommonConstant.DEL_FLAG_0);
|
||||||
|
mesXslMixerMaterialKindCfgService.save(model);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验-----------
|
||||||
|
return Result.OK("添加成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "MES密炼物料种类配置-编辑")
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-编辑")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:edit")
|
||||||
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||||
|
public Result<String> edit(@RequestBody MesXslMixerMaterialKindCfg model) {
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验-----------
|
||||||
|
String err = validateForSave(model, true);
|
||||||
|
if (err != null) {
|
||||||
|
return Result.error(err);
|
||||||
|
}
|
||||||
|
mesXslMixerMaterialKindCfgService.updateById(model);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验-----------
|
||||||
|
return Result.OK("编辑成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "MES密炼物料种类配置-删除")
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-通过id删除")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:delete")
|
||||||
|
@DeleteMapping(value = "/delete")
|
||||||
|
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
||||||
|
mesXslMixerMaterialKindCfgService.removeById(id);
|
||||||
|
return Result.OK("删除成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "MES密炼物料种类配置-批量删除")
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-批量删除")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:deleteBatch")
|
||||||
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
|
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||||
|
mesXslMixerMaterialKindCfgService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
|
return Result.OK("批量删除成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES密炼物料种类配置-通过id查询")
|
||||||
|
@GetMapping(value = "/queryById")
|
||||||
|
public Result<MesXslMixerMaterialKindCfg> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||||
|
MesXslMixerMaterialKindCfg entity = mesXslMixerMaterialKindCfgService.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return Result.error("未找到对应数据");
|
||||||
|
}
|
||||||
|
return Result.OK(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:exportXls")
|
||||||
|
@RequestMapping(value = "/exportXls")
|
||||||
|
public ModelAndView exportXls(HttpServletRequest request, MesXslMixerMaterialKindCfg model) {
|
||||||
|
return super.exportXls(request, model, MesXslMixerMaterialKindCfg.class, "密炼物料种类配置");
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixer_material_kind_cfg:importExcel")
|
||||||
|
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
||||||
|
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
return super.importExcel(request, response, MesXslMixerMaterialKindCfg.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验-----------
|
||||||
|
private String validateForSave(MesXslMixerMaterialKindCfg model, boolean isUpdate) {
|
||||||
|
if (model == null) {
|
||||||
|
return "参数不能为空";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(model.getKindKey())) {
|
||||||
|
return "种类键值不能为空";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(model.getKindName())) {
|
||||||
|
return "种类名称不能为空";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(model.getSourceType())) {
|
||||||
|
return "数据源类型不能为空";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(model.getCategoryRefId())) {
|
||||||
|
return "对应分类不能为空";
|
||||||
|
}
|
||||||
|
if (model.getPriority() == null) {
|
||||||
|
model.setPriority(999);
|
||||||
|
}
|
||||||
|
if (isUpdate && oConvertUtils.isEmpty(model.getId())) {
|
||||||
|
return "主键不能为空";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mesXslMixerMaterialKindCfgService.checkDuplicate(model, isUpdate ? model.getId() : null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return e.getMessage();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置保存校验-----------
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
package org.jeecg.modules.xslmes.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES 混炼示方
|
||||||
|
*/
|
||||||
|
@Tag(name = "MES混炼示方")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/xslmes/mesXslMixingSpec")
|
||||||
|
@Slf4j
|
||||||
|
public class MesXslMixingSpecController extends JeecgController<MesXslMixingSpec, IMesXslMixingSpecService> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslMixingSpecService mesXslMixingSpecService;
|
||||||
|
|
||||||
|
@Operation(summary = "MES混炼示方-分页列表查询")
|
||||||
|
@GetMapping(value = "/list")
|
||||||
|
public Result<IPage<MesXslMixingSpec>> queryPageList(
|
||||||
|
MesXslMixingSpec model,
|
||||||
|
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||||
|
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||||
|
@RequestParam(name = "keyword", required = false) String keyword,
|
||||||
|
HttpServletRequest req) {
|
||||||
|
QueryWrapper<MesXslMixingSpec> queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方列表关键字查询-----------
|
||||||
|
if (oConvertUtils.isNotEmpty(keyword)) {
|
||||||
|
queryWrapper.and(w -> w.like("spec_name", keyword).or().like("issue_number", keyword).or().like("purpose", keyword).or().like("machine_name", keyword));
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方列表关键字查询-----------
|
||||||
|
queryWrapper.orderByDesc("update_time").orderByDesc("create_time");
|
||||||
|
Page<MesXslMixingSpec> page = new Page<>(pageNo, pageSize);
|
||||||
|
return Result.OK(mesXslMixingSpecService.page(page, queryWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "MES混炼示方-添加")
|
||||||
|
@Operation(summary = "MES混炼示方-添加")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:add")
|
||||||
|
@PostMapping(value = "/add")
|
||||||
|
public Result<String> add(@RequestBody MesXslMixingSpecPage page) {
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
long requestStartMs = System.currentTimeMillis();
|
||||||
|
log.info(
|
||||||
|
"[混炼示方保存性能] 接口/add 收到请求 specName={}, payload=[material={}, step={}, downStep={}, tcu={}]",
|
||||||
|
page != null ? page.getSpecName() : null,
|
||||||
|
countChildRows(page != null ? page.getMaterialList() : null),
|
||||||
|
countChildRows(page != null ? page.getStepList() : null),
|
||||||
|
countChildRows(page != null ? page.getDownStepList() : null),
|
||||||
|
countChildRows(page != null ? page.getTcuList() : null));
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
String err = validateMain(page);
|
||||||
|
if (err != null) {
|
||||||
|
return Result.error(err);
|
||||||
|
}
|
||||||
|
long validateMs = System.currentTimeMillis();
|
||||||
|
MesXslMixingSpec main = new MesXslMixingSpec();
|
||||||
|
BeanUtils.copyProperties(page, main);
|
||||||
|
long copyMs = System.currentTimeMillis();
|
||||||
|
mesXslMixingSpecService.saveMain(main, page.getMaterialList(), page.getStepList(), page.getDownStepList(), page.getTcuList());
|
||||||
|
long serviceMs = System.currentTimeMillis();
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
log.info(
|
||||||
|
"[混炼示方保存性能] 接口/add 完成 specName={}, mainId={}, validate={}ms, copy={}ms, service={}ms, total={}ms(返回响应前,不含AutoLog等切面)",
|
||||||
|
main.getSpecName(),
|
||||||
|
main.getId(),
|
||||||
|
validateMs - requestStartMs,
|
||||||
|
copyMs - validateMs,
|
||||||
|
serviceMs - copyMs,
|
||||||
|
serviceMs - requestStartMs);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
return Result.OK("添加成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "MES混炼示方-编辑")
|
||||||
|
@Operation(summary = "MES混炼示方-编辑")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:edit")
|
||||||
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||||
|
public Result<String> edit(@RequestBody MesXslMixingSpecPage page) {
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
long requestStartMs = System.currentTimeMillis();
|
||||||
|
log.info(
|
||||||
|
"[混炼示方保存性能] 接口/edit 收到请求 id={}, specName={}, payload=[material={}, step={}, downStep={}, tcu={}]",
|
||||||
|
page != null ? page.getId() : null,
|
||||||
|
page != null ? page.getSpecName() : null,
|
||||||
|
countChildRows(page != null ? page.getMaterialList() : null),
|
||||||
|
countChildRows(page != null ? page.getStepList() : null),
|
||||||
|
countChildRows(page != null ? page.getDownStepList() : null),
|
||||||
|
countChildRows(page != null ? page.getTcuList() : null));
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
String err = validateMain(page);
|
||||||
|
if (err != null) {
|
||||||
|
return Result.error(err);
|
||||||
|
}
|
||||||
|
long validateMs = System.currentTimeMillis();
|
||||||
|
MesXslMixingSpec main = new MesXslMixingSpec();
|
||||||
|
BeanUtils.copyProperties(page, main);
|
||||||
|
long copyMs = System.currentTimeMillis();
|
||||||
|
mesXslMixingSpecService.updateMain(main, page.getMaterialList(), page.getStepList(), page.getDownStepList(), page.getTcuList());
|
||||||
|
long serviceMs = System.currentTimeMillis();
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
log.info(
|
||||||
|
"[混炼示方保存性能] 接口/edit 完成 id={}, specName={}, validate={}ms, copy={}ms, service={}ms, total={}ms(返回响应前,不含AutoLog等切面)",
|
||||||
|
main.getId(),
|
||||||
|
main.getSpecName(),
|
||||||
|
validateMs - requestStartMs,
|
||||||
|
copyMs - validateMs,
|
||||||
|
serviceMs - copyMs,
|
||||||
|
serviceMs - requestStartMs);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
return Result.OK("编辑成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "MES混炼示方-删除")
|
||||||
|
@Operation(summary = "MES混炼示方-通过id删除")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:delete")
|
||||||
|
@DeleteMapping(value = "/delete")
|
||||||
|
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
||||||
|
mesXslMixingSpecService.delMain(id);
|
||||||
|
return Result.OK("删除成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoLog(value = "MES混炼示方-批量删除")
|
||||||
|
@Operation(summary = "MES混炼示方-批量删除")
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:deleteBatch")
|
||||||
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
|
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||||
|
mesXslMixingSpecService.delBatchMain(Arrays.asList(ids.split(",")));
|
||||||
|
return Result.OK("批量删除成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES混炼示方-通过id查询")
|
||||||
|
@GetMapping(value = "/queryById")
|
||||||
|
public Result<MesXslMixingSpecPage> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||||
|
MesXslMixingSpecPage page = mesXslMixingSpecService.queryPageById(id);
|
||||||
|
if (page == null) {
|
||||||
|
return Result.error("未找到对应数据");
|
||||||
|
}
|
||||||
|
return Result.OK(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES混炼示方-发行编号候选")
|
||||||
|
@GetMapping(value = "/queryIssueNumberOptions")
|
||||||
|
public Result<List<Map<String, String>>> queryIssueNumberOptions(
|
||||||
|
@RequestParam(name = "keyword", required = false) String keyword) {
|
||||||
|
return Result.OK(mesXslMixingSpecService.queryIssueNumberOptions(keyword));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES混炼示方-用途候选")
|
||||||
|
@GetMapping(value = "/queryPurposeOptions")
|
||||||
|
public Result<List<Map<String, String>>> queryPurposeOptions(
|
||||||
|
@RequestParam(name = "keyword", required = false) String keyword) {
|
||||||
|
return Result.OK(mesXslMixingSpecService.queryPurposeOptions(keyword));
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:exportXls")
|
||||||
|
@RequestMapping(value = "/exportXls")
|
||||||
|
public ModelAndView exportXls(HttpServletRequest request, MesXslMixingSpec model) {
|
||||||
|
return super.exportXls(request, model, MesXslMixingSpec.class, "混炼示方");
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:importExcel")
|
||||||
|
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
||||||
|
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
return super.importExcel(request, response, MesXslMixingSpec.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子保存校验-----------
|
||||||
|
private String validateMain(MesXslMixingSpecPage page) {
|
||||||
|
if (oConvertUtils.isEmpty(page.getSpecName())) {
|
||||||
|
return "请填写规格";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(page.getPurpose())) {
|
||||||
|
return "请选择用途";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(page.getIssueNumber())) {
|
||||||
|
return "请选择发行编号";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
private static int countChildRows(List<?> rows) {
|
||||||
|
return rows == null ? 0 : rows.size();
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子保存校验-----------
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package org.jeecg.modules.xslmes.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES 密炼物料种类配置
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("mes_xsl_mixer_material_kind_cfg")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Schema(description = "MES密炼物料种类配置")
|
||||||
|
public class MesXslMixerMaterialKindCfg implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public static final String SOURCE_TYPE_DICT = "dict";
|
||||||
|
public static final String SOURCE_TYPE_CATEGORY = "category";
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Excel(name = "种类键值", width = 15)
|
||||||
|
@Schema(description = "种类键值")
|
||||||
|
private String kindKey;
|
||||||
|
|
||||||
|
@Excel(name = "种类名称", width = 20)
|
||||||
|
@Schema(description = "种类名称")
|
||||||
|
private String kindName;
|
||||||
|
|
||||||
|
@Excel(name = "数据源类型", width = 12)
|
||||||
|
@Schema(description = "数据源类型:dict/category")
|
||||||
|
private String sourceType;
|
||||||
|
|
||||||
|
@Excel(name = "根编码", width = 15)
|
||||||
|
@Schema(description = "根字典编码或分类pcode")
|
||||||
|
private String sourceRootCode;
|
||||||
|
|
||||||
|
@Excel(name = "根名称", width = 20)
|
||||||
|
@Schema(description = "根名称冗余")
|
||||||
|
private String sourceRootName;
|
||||||
|
|
||||||
|
@Schema(description = "对应分类/字典项ID")
|
||||||
|
private String categoryRefId;
|
||||||
|
|
||||||
|
@Excel(name = "对应编码", width = 15)
|
||||||
|
@Schema(description = "对应分类编码/字典项值")
|
||||||
|
private String categoryRefCode;
|
||||||
|
|
||||||
|
@Excel(name = "对应分类", width = 20)
|
||||||
|
@Schema(description = "对应分类名称冗余")
|
||||||
|
private String categoryRefName;
|
||||||
|
|
||||||
|
@Excel(name = "优先级", width = 10)
|
||||||
|
@Schema(description = "优先级(数字越小越优先)")
|
||||||
|
private Integer priority;
|
||||||
|
|
||||||
|
@Schema(description = "租户ID")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
private String sysOrgCode;
|
||||||
|
|
||||||
|
@Excel(name = "创建人", width = 15)
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
@Excel(name = "创建时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
private Integer delFlag;
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
package org.jeecg.modules.xslmes.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES 混炼示方主表
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("mes_xsl_mixing_spec")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Schema(description = "MES混炼示方")
|
||||||
|
public class MesXslMixingSpec implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Schema(description = "租户ID")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
@Excel(name = "规格", width = 16)
|
||||||
|
@Schema(description = "规格")
|
||||||
|
private String specName;
|
||||||
|
|
||||||
|
@Excel(name = "用途", width = 24)
|
||||||
|
@Schema(description = "用途")
|
||||||
|
private String purpose;
|
||||||
|
|
||||||
|
@Schema(description = "机台ID")
|
||||||
|
private String machineId;
|
||||||
|
|
||||||
|
@Excel(name = "机台", width = 14)
|
||||||
|
@Schema(description = "机台")
|
||||||
|
private String machineName;
|
||||||
|
|
||||||
|
@Excel(name = "制作日期", width = 14, format = "yyyy-MM-dd")
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Schema(description = "制作日期")
|
||||||
|
private Date makeDate;
|
||||||
|
|
||||||
|
@Excel(name = "发行编号", width = 16)
|
||||||
|
@Schema(description = "发行编号")
|
||||||
|
private String issueNumber;
|
||||||
|
|
||||||
|
@Schema(description = "换算系数")
|
||||||
|
private BigDecimal convertFactor;
|
||||||
|
|
||||||
|
@Schema(description = "填充体积")
|
||||||
|
private BigDecimal fillVolume;
|
||||||
|
|
||||||
|
@Schema(description = "回收炭黑(秒)")
|
||||||
|
private Integer recycleCarbonSec;
|
||||||
|
|
||||||
|
@Schema(description = "母胶比重")
|
||||||
|
private BigDecimal motherRubberSg;
|
||||||
|
|
||||||
|
@Schema(description = "终炼胶比重")
|
||||||
|
private BigDecimal finalRubberSg;
|
||||||
|
|
||||||
|
@Schema(description = "适用工厂")
|
||||||
|
private String applyFactory;
|
||||||
|
|
||||||
|
@Schema(description = "段数(当前/总,如2/3)")
|
||||||
|
private String stageCount;
|
||||||
|
|
||||||
|
@Schema(description = "纯混炼时间(秒)")
|
||||||
|
private Integer pureMixSec;
|
||||||
|
|
||||||
|
@Schema(description = "回收炭黑(KG)")
|
||||||
|
private BigDecimal recycleCarbonKg;
|
||||||
|
|
||||||
|
@Schema(description = "自动小料打印设定")
|
||||||
|
private String autoSmallPrintSetting;
|
||||||
|
|
||||||
|
@Schema(description = "设定车数")
|
||||||
|
private Integer setTrainCount;
|
||||||
|
|
||||||
|
@Schema(description = "侧壁水温")
|
||||||
|
private BigDecimal sideWallWaterTemp;
|
||||||
|
|
||||||
|
@Schema(description = "超时排胶时间")
|
||||||
|
private Integer overtimeDischargeSec;
|
||||||
|
|
||||||
|
@Schema(description = "超温排胶时间")
|
||||||
|
private Integer overtempDischargeSec;
|
||||||
|
|
||||||
|
@Schema(description = "超温排胶温度")
|
||||||
|
private BigDecimal overtempDischargeTemp;
|
||||||
|
|
||||||
|
@Schema(description = "卸料门水温")
|
||||||
|
private BigDecimal doorWaterTemp;
|
||||||
|
|
||||||
|
@Schema(description = "转子水温")
|
||||||
|
private BigDecimal rotorWaterTemp;
|
||||||
|
|
||||||
|
@Schema(description = "最高进料温度")
|
||||||
|
private BigDecimal maxFeedTemp;
|
||||||
|
|
||||||
|
@Schema(description = "起草人")
|
||||||
|
private String draftBy;
|
||||||
|
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@Schema(description = "起草时间")
|
||||||
|
private Date draftTime;
|
||||||
|
|
||||||
|
@Schema(description = "校对人")
|
||||||
|
private String proofreadBy;
|
||||||
|
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@Schema(description = "校对时间")
|
||||||
|
private Date proofreadTime;
|
||||||
|
|
||||||
|
@Schema(description = "审核人")
|
||||||
|
private String auditBy;
|
||||||
|
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@Schema(description = "审核时间")
|
||||||
|
private Date auditTime;
|
||||||
|
|
||||||
|
@Schema(description = "批准人")
|
||||||
|
private String approveBy;
|
||||||
|
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@Schema(description = "批准时间")
|
||||||
|
private Date approveTime;
|
||||||
|
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Schema(description = "变更日期")
|
||||||
|
private Date changeDate;
|
||||||
|
|
||||||
|
private String sysOrgCode;
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
private Integer delFlag;
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package org.jeecg.modules.xslmes.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 混炼示方明细3:下密炼机混炼条件
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("mes_xsl_mixing_spec_down_step")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Schema(description = "混炼示方下密炼机混炼条件")
|
||||||
|
public class MesXslMixingSpecDownStep implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Schema(description = "主表ID")
|
||||||
|
private String mixingSpecId;
|
||||||
|
|
||||||
|
@Schema(description = "行序")
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
|
@Schema(description = "动作")
|
||||||
|
private String actionName;
|
||||||
|
|
||||||
|
@Schema(description = "时间(秒)")
|
||||||
|
private Integer actionSec;
|
||||||
|
|
||||||
|
@Schema(description = "保护时间")
|
||||||
|
private Integer protectSec;
|
||||||
|
|
||||||
|
@Schema(description = "温度(℃)")
|
||||||
|
private BigDecimal tempC;
|
||||||
|
|
||||||
|
@Schema(description = "功率(Kw)")
|
||||||
|
private BigDecimal powerKw;
|
||||||
|
|
||||||
|
@Schema(description = "能量(Kwh)")
|
||||||
|
private BigDecimal energyKwh;
|
||||||
|
|
||||||
|
@Schema(description = "组合")
|
||||||
|
private String comboMode;
|
||||||
|
|
||||||
|
@Schema(description = "转速(rpm)")
|
||||||
|
private BigDecimal speedRpm;
|
||||||
|
|
||||||
|
@Schema(description = "压力(Mpa)")
|
||||||
|
private BigDecimal pressureMpa;
|
||||||
|
|
||||||
|
@Schema(description = "栓(%)")
|
||||||
|
private BigDecimal boltPercent;
|
||||||
|
|
||||||
|
@Schema(description = "租户ID")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
private String createBy;
|
||||||
|
private Date createTime;
|
||||||
|
private String updateBy;
|
||||||
|
private Date updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.jeecg.modules.xslmes.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 混炼示方明细1:橡胶及配合剂
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("mes_xsl_mixing_spec_material")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Schema(description = "混炼示方橡胶及配合剂")
|
||||||
|
public class MesXslMixingSpecMaterial implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Schema(description = "主表ID")
|
||||||
|
private String mixingSpecId;
|
||||||
|
|
||||||
|
@Schema(description = "行序")
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
|
@Schema(description = "物料大类")
|
||||||
|
private String materialMajor;
|
||||||
|
|
||||||
|
@Schema(description = "物料小类")
|
||||||
|
private String materialMinor;
|
||||||
|
|
||||||
|
@Schema(description = "种类")
|
||||||
|
private String materialKind;
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A55】混炼示方明细关联密炼物料ID-----------
|
||||||
|
@Schema(description = "密炼物料ID(关联mes_mixer_material.id)")
|
||||||
|
private String mixerMaterialId;
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A55】混炼示方明细关联密炼物料ID-----------
|
||||||
|
|
||||||
|
@Schema(description = "密炼物料名称")
|
||||||
|
private String mixerMaterialName;
|
||||||
|
|
||||||
|
@Schema(description = "密炼物料描述")
|
||||||
|
private String mixerMaterialDesc;
|
||||||
|
|
||||||
|
@Schema(description = "单重")
|
||||||
|
private BigDecimal unitWeight;
|
||||||
|
|
||||||
|
@Schema(description = "累计")
|
||||||
|
private BigDecimal accumWeight;
|
||||||
|
|
||||||
|
@Schema(description = "顺序")
|
||||||
|
private Integer seqNo;
|
||||||
|
|
||||||
|
@Schema(description = "租户ID")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
private String createBy;
|
||||||
|
private Date createTime;
|
||||||
|
private String updateBy;
|
||||||
|
private Date updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package org.jeecg.modules.xslmes.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 混炼示方明细2:混合步骤
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("mes_xsl_mixing_spec_step")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Schema(description = "混炼示方混合步骤")
|
||||||
|
public class MesXslMixingSpecStep implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Schema(description = "主表ID")
|
||||||
|
private String mixingSpecId;
|
||||||
|
|
||||||
|
@Schema(description = "行序")
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
|
@Schema(description = "动作")
|
||||||
|
private String actionName;
|
||||||
|
|
||||||
|
@Schema(description = "时间(秒)")
|
||||||
|
private Integer actionSec;
|
||||||
|
|
||||||
|
@Schema(description = "保护时间")
|
||||||
|
private Integer protectSec;
|
||||||
|
|
||||||
|
@Schema(description = "温度(℃)")
|
||||||
|
private BigDecimal tempC;
|
||||||
|
|
||||||
|
@Schema(description = "功率(Kw)")
|
||||||
|
private BigDecimal powerKw;
|
||||||
|
|
||||||
|
@Schema(description = "能量(Kwh)")
|
||||||
|
private BigDecimal energyKwh;
|
||||||
|
|
||||||
|
@Schema(description = "组合")
|
||||||
|
private String comboMode;
|
||||||
|
|
||||||
|
@Schema(description = "转速(rpm)")
|
||||||
|
private BigDecimal speedRpm;
|
||||||
|
|
||||||
|
@Schema(description = "压力(Mpa)")
|
||||||
|
private BigDecimal pressureMpa;
|
||||||
|
|
||||||
|
@Schema(description = "栓(%)")
|
||||||
|
private BigDecimal boltPercent;
|
||||||
|
|
||||||
|
@Schema(description = "租户ID")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
private String createBy;
|
||||||
|
private Date createTime;
|
||||||
|
private String updateBy;
|
||||||
|
private Date updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package org.jeecg.modules.xslmes.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 混炼示方明细4:TCU温度条件
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("mes_xsl_mixing_spec_tcu")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Schema(description = "混炼示方TCU温度条件")
|
||||||
|
public class MesXslMixingSpecTcu implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Schema(description = "主表ID")
|
||||||
|
private String mixingSpecId;
|
||||||
|
|
||||||
|
@Schema(description = "行序")
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
|
@Schema(description = "区分(字典xslmes_mixing_tcu_section)")
|
||||||
|
private String sectionType;
|
||||||
|
|
||||||
|
@Schema(description = "前转子温度")
|
||||||
|
private BigDecimal frontRotorTemp;
|
||||||
|
|
||||||
|
@Schema(description = "后转子温度")
|
||||||
|
private BigDecimal rearRotorTemp;
|
||||||
|
|
||||||
|
@Schema(description = "前混炼室温度")
|
||||||
|
private BigDecimal frontChamberTemp;
|
||||||
|
|
||||||
|
@Schema(description = "后混炼室温度")
|
||||||
|
private BigDecimal rearChamberTemp;
|
||||||
|
|
||||||
|
@Schema(description = "上下顶栓温度")
|
||||||
|
private BigDecimal topPlugTemp;
|
||||||
|
|
||||||
|
@Schema(description = "药品称量位置(字典xslmes_mixing_drug_weigh_pos)")
|
||||||
|
private String drugWeighPos;
|
||||||
|
|
||||||
|
@Schema(description = "租户ID")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
private String createBy;
|
||||||
|
private Date createTime;
|
||||||
|
private String updateBy;
|
||||||
|
private Date updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES 密炼物料种类配置
|
||||||
|
*/
|
||||||
|
public interface MesXslMixerMaterialKindCfgMapper extends BaseMapper<MesXslMixerMaterialKindCfg> {}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep;
|
||||||
|
|
||||||
|
public interface MesXslMixingSpecDownStepMapper extends BaseMapper<MesXslMixingSpecDownStep> {}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
|
||||||
|
|
||||||
|
public interface MesXslMixingSpecMapper extends BaseMapper<MesXslMixingSpec> {}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial;
|
||||||
|
|
||||||
|
public interface MesXslMixingSpecMaterialMapper extends BaseMapper<MesXslMixingSpecMaterial> {}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecStep;
|
||||||
|
|
||||||
|
public interface MesXslMixingSpecStepMapper extends BaseMapper<MesXslMixingSpecStep> {}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecTcu;
|
||||||
|
|
||||||
|
public interface MesXslMixingSpecTcuMapper extends BaseMapper<MesXslMixingSpecTcu> {}
|
||||||
@@ -6,6 +6,9 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec;
|
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine;
|
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewVO;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRequestVO;
|
||||||
|
|
||||||
public interface IMesXslFormulaSpecService extends IService<MesXslFormulaSpec> {
|
public interface IMesXslFormulaSpecService extends IService<MesXslFormulaSpec> {
|
||||||
|
|
||||||
@@ -25,4 +28,28 @@ public interface IMesXslFormulaSpecService extends IService<MesXslFormulaSpec> {
|
|||||||
* 生成胶料代号:D + 胶料名称 + 分类键值(S/P/T/C) + 版本号(A01-Z01)
|
* 生成胶料代号:D + 胶料名称 + 分类键值(S/P/T/C) + 版本号(A01-Z01)
|
||||||
*/
|
*/
|
||||||
String generateRubberCode(String rubberMaterialId, String category, String excludeSpecId);
|
String generateRubberCode(String rubberMaterialId, String category, String excludeSpecId);
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人-----------
|
||||||
|
/**
|
||||||
|
* 密炼PS校对/审核/批准后,按发行编号(PS编码)同步关联配合示方状态与审批人
|
||||||
|
*
|
||||||
|
* @param ps 已更新后的密炼PS编制单
|
||||||
|
* @param mixerPsTargetStatus 密炼PS目标状态:proofread / audit / approve
|
||||||
|
*/
|
||||||
|
void syncFromMixerPsWorkflow(MesXslMixerPsCompile ps, String mixerPsTargetStatus);
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方预览与批量创建-----------
|
||||||
|
/**
|
||||||
|
* 根据配合示方混合段数构建生成混炼示方预览行(示方编号 + 段信息)
|
||||||
|
*/
|
||||||
|
MesXslFormulaMixingGeneratePreviewVO buildMixingGeneratePreview(String formulaSpecId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按预览行×机台批量生成混炼示方(含橡胶及配合剂明细)
|
||||||
|
*
|
||||||
|
* @return 成功生成的混炼示方条数
|
||||||
|
*/
|
||||||
|
int generateMixingSpecFromFormula(MesXslFormulaMixingGenerateRequestVO request);
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方预览与批量创建-----------
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package org.jeecg.modules.xslmes.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import java.util.List;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslMixerMaterialKindLookupVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES 密炼物料种类配置
|
||||||
|
*/
|
||||||
|
public interface IMesXslMixerMaterialKindCfgService extends IService<MesXslMixerMaterialKindCfg> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按根字典/分类展开明细行(未持久化)
|
||||||
|
*/
|
||||||
|
List<MesXslMixerMaterialKindCfg> expandLines(String sourceType, String sourceRootCode, Integer tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量新增
|
||||||
|
*/
|
||||||
|
void saveBatchLines(List<MesXslMixerMaterialKindCfg> lines, Integer tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验租户内种类键值/对应分类是否重复
|
||||||
|
*/
|
||||||
|
void checkDuplicate(MesXslMixerMaterialKindCfg line, String excludeId);
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||||
|
/**
|
||||||
|
* 加载种类配置查找表(按 category_ref_id / category_ref_code 关联)
|
||||||
|
*/
|
||||||
|
MesXslMixerMaterialKindLookupVO loadKindLookup(Integer tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析混炼示方明细种类:称量方式优先,其次物料小类 ID;未命中配置返回 null
|
||||||
|
*/
|
||||||
|
String resolveMixingMaterialKind(
|
||||||
|
MesXslMixerMaterialKindLookupVO lookup,
|
||||||
|
String minorCategoryId,
|
||||||
|
String weighMode,
|
||||||
|
String minorCategoryName);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package org.jeecg.modules.xslmes.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecStep;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecTcu;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
|
||||||
|
|
||||||
|
public interface IMesXslMixingSpecService extends IService<MesXslMixingSpec> {
|
||||||
|
void saveMain(
|
||||||
|
MesXslMixingSpec main,
|
||||||
|
List<MesXslMixingSpecMaterial> materialList,
|
||||||
|
List<MesXslMixingSpecStep> stepList,
|
||||||
|
List<MesXslMixingSpecDownStep> downStepList,
|
||||||
|
List<MesXslMixingSpecTcu> tcuList);
|
||||||
|
|
||||||
|
void updateMain(
|
||||||
|
MesXslMixingSpec main,
|
||||||
|
List<MesXslMixingSpecMaterial> materialList,
|
||||||
|
List<MesXslMixingSpecStep> stepList,
|
||||||
|
List<MesXslMixingSpecDownStep> downStepList,
|
||||||
|
List<MesXslMixingSpecTcu> tcuList);
|
||||||
|
|
||||||
|
void delMain(String id);
|
||||||
|
|
||||||
|
void delBatchMain(Collection<? extends Serializable> idList);
|
||||||
|
|
||||||
|
MesXslMixingSpecPage queryPageById(String id);
|
||||||
|
|
||||||
|
List<Map<String, String>> queryIssueNumberOptions(String keyword);
|
||||||
|
|
||||||
|
List<Map<String, String>> queryPurposeOptions(String keyword);
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import jakarta.annotation.Resource;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -14,6 +15,8 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -21,24 +24,49 @@ import org.jeecg.modules.mes.material.entity.MesMaterial;
|
|||||||
import org.jeecg.modules.mes.material.entity.MesMixerMaterial;
|
import org.jeecg.modules.mes.material.entity.MesMixerMaterial;
|
||||||
import org.jeecg.modules.mes.material.service.IMesMaterialService;
|
import org.jeecg.modules.mes.material.service.IMesMaterialService;
|
||||||
import org.jeecg.modules.mes.material.service.IMesMixerMaterialService;
|
import org.jeecg.modules.mes.material.service.IMesMixerMaterialService;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.modules.system.entity.SysCategory;
|
||||||
|
import org.jeecg.modules.system.service.ISysCategoryService;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslEquipmentLedger;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec;
|
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine;
|
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial;
|
||||||
import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecLineMapper;
|
import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecLineMapper;
|
||||||
import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecMapper;
|
import org.jeecg.modules.xslmes.mapper.MesXslFormulaSpecMapper;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslEquipmentLedgerService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService;
|
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService;
|
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecSettingService;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslMixerMaterialKindCfgService;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslMixerMaterialKindLookupVO;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateMachineVO;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewItemVO;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGeneratePreviewVO;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRequestVO;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslFormulaMixingGenerateRowVO;
|
||||||
import org.jeecg.modules.system.entity.SysUser;
|
import org.jeecg.modules.system.entity.SysUser;
|
||||||
import org.jeecg.modules.system.service.ISysUserService;
|
import org.jeecg.modules.system.service.ISysUserService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecMapper, MesXslFormulaSpec>
|
public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecMapper, MesXslFormulaSpec>
|
||||||
implements IMesXslFormulaSpecService {
|
implements IMesXslFormulaSpecService {
|
||||||
|
|
||||||
private static final Set<String> RUBBER_CATEGORY_KEYS = Set.of("S", "P", "T", "C");
|
private static final Set<String> RUBBER_CATEGORY_KEYS = Set.of("S", "P", "T", "C");
|
||||||
private static final Pattern RUBBER_CODE_VERSION_PATTERN = Pattern.compile("([A-Z])01$");
|
private static final Pattern RUBBER_CODE_VERSION_PATTERN = Pattern.compile("([A-Z])01$");
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||||
|
private static final String CATEGORY_MASTER_MAJOR = "XSLMES_MATERIAL_MASTER";
|
||||||
|
private static final String CATEGORY_MASTER_MINOR_A = "XSLMES_MATERIAL_MASTER_A";
|
||||||
|
private static final String CATEGORY_FINAL_MAJOR = "XSLMES_MATERIAL_FINAL";
|
||||||
|
private static final String CATEGORY_FINAL_MINOR_Q = "XSLMES_MATERIAL_FINAL_Q";
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private MesXslFormulaSpecLineMapper lineMapper;
|
private MesXslFormulaSpecLineMapper lineMapper;
|
||||||
@@ -55,6 +83,18 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
|||||||
@Resource
|
@Resource
|
||||||
private ISysUserService sysUserService;
|
private ISysUserService sysUserService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IMesXslMixingSpecService mesXslMixingSpecService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IMesXslEquipmentLedgerService mesXslEquipmentLedgerService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ISysCategoryService sysCategoryService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IMesXslMixerMaterialKindCfgService mesXslMixerMaterialKindCfgService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void saveMain(MesXslFormulaSpec main, List<MesXslFormulaSpecLine> lineList) {
|
public void saveMain(MesXslFormulaSpec main, List<MesXslFormulaSpecLine> lineList) {
|
||||||
@@ -400,4 +440,844 @@ public class MesXslFormulaSpecServiceImpl extends ServiceImpl<MesXslFormulaSpecM
|
|||||||
return line.getPhr().divide(material.getSpecificGravity(), 6, RoundingMode.HALF_UP);
|
return line.getPhr().divide(material.getSpecificGravity(), 6, RoundingMode.HALF_UP);
|
||||||
}
|
}
|
||||||
//update-end---author:cursor ---date:20260521 for:【配合示方】保存后汇总A/Q胶比重写入数据库-----------
|
//update-end---author:cursor ---date:20260521 for:【配合示方】保存后汇总A/Q胶比重写入数据库-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人-----------
|
||||||
|
@Override
|
||||||
|
public void syncFromMixerPsWorkflow(MesXslMixerPsCompile ps, String mixerPsTargetStatus) {
|
||||||
|
if (ps == null || oConvertUtils.isEmpty(ps.getPsCode()) || oConvertUtils.isEmpty(mixerPsTargetStatus)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LambdaUpdateWrapper<MesXslFormulaSpec> wrapper = new LambdaUpdateWrapper<>();
|
||||||
|
wrapper.eq(MesXslFormulaSpec::getIssueNumber, ps.getPsCode());
|
||||||
|
switch (mixerPsTargetStatus) {
|
||||||
|
case "proofread":
|
||||||
|
wrapper.set(MesXslFormulaSpec::getStatus, "submit")
|
||||||
|
.set(MesXslFormulaSpec::getProofreadBy, ps.getProofreadBy())
|
||||||
|
.set(MesXslFormulaSpec::getProofreadTime, ps.getProofreadTime());
|
||||||
|
break;
|
||||||
|
case "audit":
|
||||||
|
wrapper.set(MesXslFormulaSpec::getStatus, "review_pass")
|
||||||
|
.set(MesXslFormulaSpec::getAuditBy, ps.getAuditBy())
|
||||||
|
.set(MesXslFormulaSpec::getAuditTime, ps.getAuditTime());
|
||||||
|
break;
|
||||||
|
case "approve":
|
||||||
|
wrapper.set(MesXslFormulaSpec::getStatus, "recognition_pass")
|
||||||
|
.set(MesXslFormulaSpec::getApproveBy, ps.getApproveBy())
|
||||||
|
.set(MesXslFormulaSpec::getApproveTime, ps.getApproveTime());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wrapper.set(MesXslFormulaSpec::getUpdateTime, new Date());
|
||||||
|
this.update(wrapper);
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方预览与批量创建-----------
|
||||||
|
@Override
|
||||||
|
public MesXslFormulaMixingGeneratePreviewVO buildMixingGeneratePreview(String formulaSpecId) {
|
||||||
|
MesXslFormulaSpec main = getByIdWithLines(formulaSpecId);
|
||||||
|
if (main == null) {
|
||||||
|
throw new IllegalArgumentException("未找到配合示方数据");
|
||||||
|
}
|
||||||
|
int stageCount = normalizeMixingStages(main.getMixingStages());
|
||||||
|
if (stageCount <= 0) {
|
||||||
|
throw new IllegalArgumentException("请先维护混合段数");
|
||||||
|
}
|
||||||
|
String rubberName = resolveRubberName(main);
|
||||||
|
String formulaCodeSuffix = resolveFormulaCodeSuffix(main);
|
||||||
|
boolean hasQ = hasStepQ(main.getLineList());
|
||||||
|
List<MesXslFormulaMixingGeneratePreviewItemVO> items = new ArrayList<>();
|
||||||
|
int aIndex = 0;
|
||||||
|
for (int i = 1; i <= stageCount; i++) {
|
||||||
|
boolean isQSegment = hasQ && i == stageCount;
|
||||||
|
MesXslFormulaMixingGeneratePreviewItemVO item = new MesXslFormulaMixingGeneratePreviewItemVO();
|
||||||
|
item.setRowKey(i);
|
||||||
|
item.setStageIndex(i);
|
||||||
|
if (isQSegment) {
|
||||||
|
item.setStepType("Q");
|
||||||
|
item.setSpecCode(appendFormulaCodeSuffix("F" + rubberName, formulaCodeSuffix));
|
||||||
|
item.setASegmentIndex(null);
|
||||||
|
} else {
|
||||||
|
aIndex++;
|
||||||
|
item.setStepType("A");
|
||||||
|
item.setASegmentIndex(aIndex);
|
||||||
|
item.setSpecCode(appendFormulaCodeSuffix("B" + aIndex + rubberName, formulaCodeSuffix));
|
||||||
|
}
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
MesXslFormulaMixingGeneratePreviewVO preview = new MesXslFormulaMixingGeneratePreviewVO();
|
||||||
|
preview.setFormulaSpecId(formulaSpecId);
|
||||||
|
preview.setRubberName(rubberName);
|
||||||
|
preview.setMixingStages(stageCount);
|
||||||
|
preview.setItems(items);
|
||||||
|
return preview;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int generateMixingSpecFromFormula(MesXslFormulaMixingGenerateRequestVO request) {
|
||||||
|
if (request == null || oConvertUtils.isEmpty(request.getFormulaSpecId())) {
|
||||||
|
throw new IllegalArgumentException("配合示方ID不能为空");
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(request.getRows())) {
|
||||||
|
throw new IllegalArgumentException("请至少配置一行示方与机台");
|
||||||
|
}
|
||||||
|
MesXslFormulaSpec formula = getByIdWithLines(request.getFormulaSpecId());
|
||||||
|
if (formula == null) {
|
||||||
|
throw new IllegalArgumentException("未找到配合示方数据");
|
||||||
|
}
|
||||||
|
List<MesXslFormulaSpecLine> lines = formula.getLineList();
|
||||||
|
if (CollectionUtils.isEmpty(lines)) {
|
||||||
|
throw new IllegalArgumentException("配合示方明细为空,无法生成混炼示方");
|
||||||
|
}
|
||||||
|
Map<String, MesMixerMaterial> mixerCache = new HashMap<>();
|
||||||
|
Map<String, String> categoryNameCache = new HashMap<>();
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】生成混炼示方种类改读密炼物料种类配置-----------
|
||||||
|
MesXslMixerMaterialKindLookupVO kindLookup = mesXslMixerMaterialKindCfgService.loadKindLookup(null);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】生成混炼示方种类改读密炼物料种类配置-----------
|
||||||
|
Map<String, MesXslEquipmentLedger> equipmentCache = new HashMap<>();
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】F段终炼胶比重按配合示方整体PHR/体积汇总-----------
|
||||||
|
BigDecimal compoundSpecificGravity = resolveCompoundSpecificGravity(formula, lines);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】F段终炼胶比重按配合示方整体PHR/体积汇总-----------
|
||||||
|
int created = 0;
|
||||||
|
int totalStages = normalizeMixingStages(formula.getMixingStages());
|
||||||
|
Date today = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||||
|
Set<String> syncedRubberSpecCodes = new HashSet<>();
|
||||||
|
Map<String, String> categoryIdCache = new HashMap<>();
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||||
|
for (MesXslFormulaMixingGenerateRowVO row : request.getRows()) {
|
||||||
|
if (row == null || oConvertUtils.isEmpty(row.getSpecCode()) || row.getStageIndex() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(row.getMachines())) {
|
||||||
|
throw new IllegalArgumentException("示方「" + row.getSpecCode() + "」请至少选择一个机台");
|
||||||
|
}
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||||
|
if (syncedRubberSpecCodes.add(row.getSpecCode().trim())) {
|
||||||
|
syncGeneratedRubberMixerMaterial(row, formula, compoundSpecificGravity, categoryIdCache);
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||||
|
String materialStep = resolveMixingMaterialStep(row);
|
||||||
|
int mixingColumn = resolveMixingColumn(row, formula);
|
||||||
|
List<MesXslMixingSpecMaterial> materials = buildMixingMaterials(
|
||||||
|
formula,
|
||||||
|
lines,
|
||||||
|
mixingColumn,
|
||||||
|
materialStep,
|
||||||
|
mixerCache,
|
||||||
|
categoryNameCache,
|
||||||
|
kindLookup,
|
||||||
|
compoundSpecificGravity,
|
||||||
|
categoryIdCache);
|
||||||
|
for (MesXslFormulaMixingGenerateMachineVO machine : row.getMachines()) {
|
||||||
|
if (machine == null || oConvertUtils.isEmpty(machine.getMachineId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
MesXslMixingSpec mixing = new MesXslMixingSpec();
|
||||||
|
mixing.setSpecName(row.getSpecCode());
|
||||||
|
mixing.setPurpose(formula.getPurpose());
|
||||||
|
mixing.setIssueNumber(formula.getIssueNumber());
|
||||||
|
mixing.setMachineId(machine.getMachineId());
|
||||||
|
mixing.setMachineName(machine.getMachineName());
|
||||||
|
mixing.setMakeDate(today);
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A40】生成时写入段数当前/总如2/3-----------
|
||||||
|
if (row.getStageIndex() != null && totalStages > 0) {
|
||||||
|
mixing.setStageCount(row.getStageIndex() + "/" + totalStages);
|
||||||
|
} else if (row.getStageIndex() != null) {
|
||||||
|
mixing.setStageCount(String.valueOf(row.getStageIndex()));
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A40】生成时写入段数当前/总如2/3-----------
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】生成混炼示方时按设备有效体积计算填充体积-----------
|
||||||
|
mixing.setConvertFactor(BigDecimal.ONE);
|
||||||
|
boolean isFinalStage = "Q".equalsIgnoreCase(row.getStepType());
|
||||||
|
if (isFinalStage) {
|
||||||
|
mixing.setFinalRubberSg(compoundSpecificGravity);
|
||||||
|
} else {
|
||||||
|
mixing.setMotherRubberSg(formula.getARubberSg());
|
||||||
|
}
|
||||||
|
BigDecimal specificGravity = isFinalStage ? compoundSpecificGravity : formula.getARubberSg();
|
||||||
|
String machineLabel = StringUtils.defaultIfBlank(machine.getMachineName(), machine.getMachineId());
|
||||||
|
MesXslEquipmentLedger equipment = equipmentCache.computeIfAbsent(
|
||||||
|
machine.getMachineId(), mesXslEquipmentLedgerService::getById);
|
||||||
|
if (equipment == null) {
|
||||||
|
throw new IllegalArgumentException("机台「" + machineLabel + "」不存在或已删除,无法生成混炼示方");
|
||||||
|
}
|
||||||
|
BigDecimal effectiveVolume = parseEffectiveVolume(equipment.getEffectiveVolume(), machineLabel);
|
||||||
|
BigDecimal totalWeight = sumMaterialUnitWeight(materials);
|
||||||
|
mixing.setFillVolume(calcFillVolume(totalWeight, specificGravity, effectiveVolume, mixing.getConvertFactor()));
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】生成混炼示方时按设备有效体积计算填充体积-----------
|
||||||
|
mesXslMixingSpecService.saveMain(mixing, materials, null, null, null);
|
||||||
|
created++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (created <= 0) {
|
||||||
|
throw new IllegalArgumentException("未生成任何混炼示方,请检查机台配置");
|
||||||
|
}
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】生成混炼示方时按设备有效体积计算填充体积-----------
|
||||||
|
/** 配合示方整体比重(终炼胶比重)= TOTAL PHR ÷ 全部明细体积合计 */
|
||||||
|
private BigDecimal resolveCompoundSpecificGravity(MesXslFormulaSpec formula, List<MesXslFormulaSpecLine> lines) {
|
||||||
|
if (CollectionUtils.isEmpty(lines)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BigDecimal totalPhr = formula != null && formula.getTotalPhr() != null && formula.getTotalPhr().compareTo(BigDecimal.ZERO) > 0
|
||||||
|
? formula.getTotalPhr()
|
||||||
|
: BigDecimal.ZERO;
|
||||||
|
if (totalPhr.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
for (MesXslFormulaSpecLine line : lines) {
|
||||||
|
if (line != null && line.getPhr() != null) {
|
||||||
|
totalPhr = totalPhr.add(line.getPhr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BigDecimal totalVolume = BigDecimal.ZERO;
|
||||||
|
for (MesXslFormulaSpecLine line : lines) {
|
||||||
|
BigDecimal volume = resolveLineVolume(line);
|
||||||
|
if (volume != null) {
|
||||||
|
totalVolume = totalVolume.add(volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (totalPhr.compareTo(BigDecimal.ZERO) <= 0 || totalVolume.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return totalPhr.divide(totalVolume, 6, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 解析设备台账有效体积(支持纯数字或带单位的字符串) */
|
||||||
|
private BigDecimal parseEffectiveVolume(String raw, String machineLabel) {
|
||||||
|
if (StringUtils.isBlank(raw)) {
|
||||||
|
throw new IllegalArgumentException("机台「" + machineLabel + "」未维护有效体积,无法计算填充体积");
|
||||||
|
}
|
||||||
|
String trimmed = raw.trim();
|
||||||
|
try {
|
||||||
|
BigDecimal value = new BigDecimal(trimmed);
|
||||||
|
if (value.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
throw new IllegalArgumentException("机台「" + machineLabel + "」有效体积必须大于 0");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
Matcher matcher = Pattern.compile("([0-9]+(?:\\.[0-9]+)?)").matcher(trimmed);
|
||||||
|
if (matcher.find()) {
|
||||||
|
BigDecimal value = new BigDecimal(matcher.group(1));
|
||||||
|
if (value.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
throw new IllegalArgumentException("机台「" + machineLabel + "」有效体积必须大于 0");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("机台「" + machineLabel + "」有效体积格式无效:" + raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 橡胶及配合剂明细单重合计 */
|
||||||
|
private BigDecimal sumMaterialUnitWeight(List<MesXslMixingSpecMaterial> materials) {
|
||||||
|
if (CollectionUtils.isEmpty(materials)) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
BigDecimal total = BigDecimal.ZERO;
|
||||||
|
for (MesXslMixingSpecMaterial material : materials) {
|
||||||
|
if (material != null && material.getUnitWeight() != null) {
|
||||||
|
total = total.add(material.getUnitWeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 填充体积(%) = 本段单重合计 ÷ 本段比重 ÷ 机台有效体积(L) × 100 × 换算系数
|
||||||
|
*/
|
||||||
|
private BigDecimal calcFillVolume(
|
||||||
|
BigDecimal totalWeight,
|
||||||
|
BigDecimal specificGravity,
|
||||||
|
BigDecimal effectiveVolume,
|
||||||
|
BigDecimal convertFactor) {
|
||||||
|
if (totalWeight == null || totalWeight.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
throw new IllegalArgumentException("本段橡胶及配合剂单重合计无效,无法计算填充体积");
|
||||||
|
}
|
||||||
|
if (specificGravity == null || specificGravity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
throw new IllegalArgumentException("本段比重无效,无法计算填充体积");
|
||||||
|
}
|
||||||
|
if (effectiveVolume == null || effectiveVolume.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
throw new IllegalArgumentException("机台有效体积无效,无法计算填充体积");
|
||||||
|
}
|
||||||
|
BigDecimal factor = convertFactor == null || convertFactor.compareTo(BigDecimal.ZERO) <= 0
|
||||||
|
? BigDecimal.ONE
|
||||||
|
: convertFactor;
|
||||||
|
BigDecimal materialVolume = totalWeight.divide(specificGravity, 6, RoundingMode.HALF_UP);
|
||||||
|
return materialVolume
|
||||||
|
.divide(effectiveVolume, 6, RoundingMode.HALF_UP)
|
||||||
|
.multiply(BigDecimal.valueOf(100))
|
||||||
|
.multiply(factor)
|
||||||
|
.setScale(6, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A44】生成混炼示方时按设备有效体积计算填充体积-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||||
|
/**
|
||||||
|
* 生成混炼示方时,将 B 段/F 段胶料同步写入密炼物料:
|
||||||
|
* B 段 -> 物料大类「母炼胶」+ 小类「A胶」;F 段 -> 物料大类「终炼胶」+ 小类「Q胶」。
|
||||||
|
*/
|
||||||
|
private void syncGeneratedRubberMixerMaterial(
|
||||||
|
MesXslFormulaMixingGenerateRowVO row,
|
||||||
|
MesXslFormulaSpec formula,
|
||||||
|
BigDecimal compoundSpecificGravity,
|
||||||
|
Map<String, String> categoryIdCache) {
|
||||||
|
if (row == null || StringUtils.isBlank(row.getSpecCode())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String specCode = row.getSpecCode().trim();
|
||||||
|
boolean isFinalStage = "Q".equalsIgnoreCase(resolveMixingMaterialStep(row));
|
||||||
|
String majorCode = isFinalStage ? CATEGORY_FINAL_MAJOR : CATEGORY_MASTER_MAJOR;
|
||||||
|
String minorCode = isFinalStage ? CATEGORY_FINAL_MINOR_Q : CATEGORY_MASTER_MINOR_A;
|
||||||
|
String majorCategoryId = resolveCategoryIdByCode(majorCode, categoryIdCache);
|
||||||
|
String minorCategoryId = resolveCategoryIdByCode(minorCode, categoryIdCache);
|
||||||
|
if (StringUtils.isBlank(majorCategoryId) || StringUtils.isBlank(minorCategoryId)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"未找到物料分类「" + (isFinalStage ? "终炼胶/Q胶" : "母炼胶/A胶") + "」,请先维护 MES 物料分类字典");
|
||||||
|
}
|
||||||
|
BigDecimal specificGravity = isFinalStage ? compoundSpecificGravity : formula.getARubberSg();
|
||||||
|
String rubberName = resolveRubberName(formula);
|
||||||
|
String materialDesc = StringUtils.isNotBlank(formula.getPurpose()) ? formula.getPurpose().trim() : rubberName;
|
||||||
|
|
||||||
|
MesMixerMaterial existing = findMixerMaterialByCodeOrName(specCode);
|
||||||
|
Date now = new Date();
|
||||||
|
if (existing != null) {
|
||||||
|
existing.setMajorCategoryId(majorCategoryId);
|
||||||
|
existing.setMinorCategoryId(minorCategoryId);
|
||||||
|
existing.setSpecificGravity(specificGravity);
|
||||||
|
if (StringUtils.isNotBlank(materialDesc)) {
|
||||||
|
existing.setMaterialDesc(materialDesc);
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(existing.getMaterialCode())) {
|
||||||
|
existing.setMaterialCode(specCode);
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(existing.getMaterialName())) {
|
||||||
|
existing.setMaterialName(specCode);
|
||||||
|
}
|
||||||
|
existing.setUseStatus(existing.getUseStatus() == null ? 1 : existing.getUseStatus());
|
||||||
|
existing.setUpdateTime(now);
|
||||||
|
mesMixerMaterialService.updateById(existing);
|
||||||
|
log.info(
|
||||||
|
"[混炼示方生成] 更新密炼物料 id={}, code={}, major={}, minor={}, sg={}",
|
||||||
|
existing.getId(),
|
||||||
|
specCode,
|
||||||
|
majorCode,
|
||||||
|
minorCode,
|
||||||
|
specificGravity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MesMixerMaterial material = new MesMixerMaterial();
|
||||||
|
material.setMaterialCode(specCode);
|
||||||
|
material.setMaterialName(specCode);
|
||||||
|
material.setMaterialDesc(materialDesc);
|
||||||
|
material.setAliasName(StringUtils.isNotBlank(rubberName) ? rubberName : null);
|
||||||
|
material.setMajorCategoryId(majorCategoryId);
|
||||||
|
material.setMinorCategoryId(minorCategoryId);
|
||||||
|
material.setSpecificGravity(specificGravity);
|
||||||
|
material.setFeedManageStatus(0);
|
||||||
|
material.setUseStatus(1);
|
||||||
|
material.setDelFlag(CommonConstant.DEL_FLAG_0);
|
||||||
|
material.setCreateTime(now);
|
||||||
|
material.setUpdateTime(now);
|
||||||
|
mesMixerMaterialService.save(material);
|
||||||
|
log.info(
|
||||||
|
"[混炼示方生成] 新增密炼物料 id={}, code={}, major={}, minor={}, sg={}",
|
||||||
|
material.getId(),
|
||||||
|
specCode,
|
||||||
|
majorCode,
|
||||||
|
minorCode,
|
||||||
|
specificGravity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MesMixerMaterial findMixerMaterialByCodeOrName(String specCode) {
|
||||||
|
MesMixerMaterial byCode = mesMixerMaterialService.getOne(
|
||||||
|
new LambdaQueryWrapper<MesMixerMaterial>()
|
||||||
|
.eq(MesMixerMaterial::getMaterialCode, specCode)
|
||||||
|
.and(w -> w.eq(MesMixerMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMixerMaterial::getDelFlag))
|
||||||
|
.last("limit 1"));
|
||||||
|
if (byCode != null) {
|
||||||
|
return byCode;
|
||||||
|
}
|
||||||
|
return mesMixerMaterialService.getOne(
|
||||||
|
new LambdaQueryWrapper<MesMixerMaterial>()
|
||||||
|
.eq(MesMixerMaterial::getMaterialName, specCode)
|
||||||
|
.and(w -> w.eq(MesMixerMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMixerMaterial::getDelFlag))
|
||||||
|
.last("limit 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveCategoryIdByCode(String categoryCode, Map<String, String> cache) {
|
||||||
|
if (StringUtils.isBlank(categoryCode)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (cache != null && cache.containsKey(categoryCode)) {
|
||||||
|
return cache.get(categoryCode);
|
||||||
|
}
|
||||||
|
SysCategory category = sysCategoryService.getOne(
|
||||||
|
new LambdaQueryWrapper<SysCategory>().eq(SysCategory::getCode, categoryCode.trim()).last("limit 1"));
|
||||||
|
String categoryId = category != null ? category.getId() : null;
|
||||||
|
if (cache != null) {
|
||||||
|
cache.put(categoryCode, categoryId);
|
||||||
|
}
|
||||||
|
return categoryId;
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A48】生成混炼示方同步B/F段胶至密炼物料-----------
|
||||||
|
|
||||||
|
private int normalizeMixingStages(Integer mixingStages) {
|
||||||
|
if (mixingStages == null || mixingStages <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Math.min(mixingStages, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveRubberName(MesXslFormulaSpec main) {
|
||||||
|
if (StringUtils.isNotBlank(main.getBasicFormula())) {
|
||||||
|
return main.getBasicFormula().trim();
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(main.getRubberMaterialId())) {
|
||||||
|
MesMaterial rubber = mesMaterialService.getById(main.getRubberMaterialId());
|
||||||
|
if (rubber != null && StringUtils.isNotBlank(rubber.getMaterialName())) {
|
||||||
|
return rubber.getMaterialName().trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配合示方胶料代号/示方编号中,胶料名称之后的后缀原样截取(如 SA01、SB01 等,不做固定拼接)。
|
||||||
|
*/
|
||||||
|
private String resolveFormulaCodeSuffix(MesXslFormulaSpec main) {
|
||||||
|
if (main == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String code = StringUtils.isNotBlank(main.getRubberCode()) ? main.getRubberCode().trim() : "";
|
||||||
|
if (StringUtils.isBlank(code) && StringUtils.isNotBlank(main.getSpecCode())) {
|
||||||
|
code = main.getSpecCode().trim();
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(code)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String rubberName = resolveRubberName(main);
|
||||||
|
if (StringUtils.isBlank(rubberName)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int nameIndex = code.indexOf(rubberName);
|
||||||
|
if (nameIndex >= 0 && nameIndex + rubberName.length() < code.length()) {
|
||||||
|
return code.substring(nameIndex + rubberName.length());
|
||||||
|
}
|
||||||
|
String dNamePrefix = "D" + rubberName;
|
||||||
|
if (code.startsWith(dNamePrefix) && code.length() > dNamePrefix.length()) {
|
||||||
|
return code.substring(dNamePrefix.length());
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String appendFormulaCodeSuffix(String baseSpecCode, String formulaCodeSuffix) {
|
||||||
|
if (StringUtils.isBlank(baseSpecCode)) {
|
||||||
|
return baseSpecCode;
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(formulaCodeSuffix)) {
|
||||||
|
return baseSpecCode;
|
||||||
|
}
|
||||||
|
return baseSpecCode + formulaCodeSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasStepQ(List<MesXslFormulaSpecLine> lines) {
|
||||||
|
if (CollectionUtils.isEmpty(lines)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (MesXslFormulaSpecLine line : lines) {
|
||||||
|
if (line != null && "Q".equalsIgnoreCase(line.getStep())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 解析 B/F 段对应的配合示方混合段列号 */
|
||||||
|
private int resolveMixingColumn(MesXslFormulaMixingGenerateRowVO row, MesXslFormulaSpec formula) {
|
||||||
|
if ("Q".equalsIgnoreCase(resolveMixingMaterialStep(row))) {
|
||||||
|
Integer stages = formula != null ? formula.getMixingStages() : null;
|
||||||
|
if (stages != null && stages > 0) {
|
||||||
|
return Math.min(stages, 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (row != null && row.getASegmentIndex() != null && row.getASegmentIndex() > 0) {
|
||||||
|
return Math.min(row.getASegmentIndex(), 7);
|
||||||
|
}
|
||||||
|
if (row != null && row.getStageIndex() != null && row.getStageIndex() > 0) {
|
||||||
|
return Math.min(row.getStageIndex(), 7);
|
||||||
|
}
|
||||||
|
String specCode = row != null ? row.getSpecCode() : null;
|
||||||
|
if (StringUtils.isNotBlank(specCode)) {
|
||||||
|
Matcher matcher = Pattern.compile("(?i)B(\\d+)").matcher(specCode.trim());
|
||||||
|
if (matcher.find()) {
|
||||||
|
return Math.min(Integer.parseInt(matcher.group(1)), 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* B1=第一段配合剂(列1 STEP=A);Bn(n>1)=上一段胶料示方一条(B{n-1}+胶料名)+本段列n配合剂。
|
||||||
|
* F 段=最后一段B炼好胶一条(如三段时B2+胶料名)+本列 STEP=Q 配合剂。
|
||||||
|
*/
|
||||||
|
private String resolveMixingMaterialStep(MesXslFormulaMixingGenerateRowVO row) {
|
||||||
|
if (row != null && StringUtils.isNotBlank(row.getStepType())) {
|
||||||
|
return row.getStepType().trim().toUpperCase();
|
||||||
|
}
|
||||||
|
String specCode = row != null ? row.getSpecCode() : null;
|
||||||
|
if (StringUtils.isNotBlank(specCode) && specCode.trim().toUpperCase().startsWith("F")) {
|
||||||
|
return "Q";
|
||||||
|
}
|
||||||
|
return "A";
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MesXslMixingSpecMaterial> buildMixingMaterials(
|
||||||
|
MesXslFormulaSpec formula,
|
||||||
|
List<MesXslFormulaSpecLine> lines,
|
||||||
|
int stageIndex,
|
||||||
|
String materialStep,
|
||||||
|
Map<String, MesMixerMaterial> mixerCache,
|
||||||
|
Map<String, String> categoryNameCache,
|
||||||
|
MesXslMixerMaterialKindLookupVO kindLookup,
|
||||||
|
BigDecimal compoundSpecificGravity,
|
||||||
|
Map<String, String> categoryIdCache) {
|
||||||
|
String stepFilter = StringUtils.isNotBlank(materialStep) ? materialStep.trim().toUpperCase() : "A";
|
||||||
|
List<MesXslMixingSpecMaterial> materials = new ArrayList<>();
|
||||||
|
int sort = 0;
|
||||||
|
if ("Q".equals(stepFilter)) {
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】F段加入最后一段B炼好胶料一条再加Q配合剂-----------
|
||||||
|
String rubberName = resolveRubberName(formula);
|
||||||
|
String codeSuffix = resolveFormulaCodeSuffix(formula);
|
||||||
|
int lastBSegment = resolveLastBSegmentIndex(formula, lines);
|
||||||
|
if (lastBSegment > 0) {
|
||||||
|
String motherSpecCode = appendFormulaCodeSuffix("B" + lastBSegment + rubberName, codeSuffix);
|
||||||
|
BigDecimal motherWeight = resolveStageCumulativeTotal(formula, lines, lastBSegment);
|
||||||
|
materials.add(
|
||||||
|
createMotherRubberMaterial(
|
||||||
|
motherSpecCode,
|
||||||
|
motherWeight,
|
||||||
|
materials.size(),
|
||||||
|
formula,
|
||||||
|
compoundSpecificGravity,
|
||||||
|
categoryIdCache,
|
||||||
|
mixerCache,
|
||||||
|
categoryNameCache,
|
||||||
|
kindLookup));
|
||||||
|
}
|
||||||
|
appendQStageColumnAgents(lines, stageIndex, materials, mixerCache, categoryNameCache, kindLookup);
|
||||||
|
reindexMaterialSortNo(materials);
|
||||||
|
return materials;
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】F段加入最后一段B炼好胶料一条再加Q配合剂-----------
|
||||||
|
}
|
||||||
|
int bColumn = Math.max(stageIndex, 1);
|
||||||
|
String rubberName = resolveRubberName(formula);
|
||||||
|
String codeSuffix = resolveFormulaCodeSuffix(formula);
|
||||||
|
if (bColumn <= 1) {
|
||||||
|
appendBStageColumnAgents(lines, 1, materials, mixerCache, categoryNameCache, kindLookup);
|
||||||
|
reindexMaterialSortNo(materials);
|
||||||
|
return materials;
|
||||||
|
}
|
||||||
|
// B2/B3…:上一段炼好胶料一条(如 B1+胶料名) + 本段列配合剂
|
||||||
|
int prevB = bColumn - 1;
|
||||||
|
String motherSpecCode = appendFormulaCodeSuffix("B" + prevB + rubberName, codeSuffix);
|
||||||
|
BigDecimal motherWeight = resolveStageCumulativeTotal(formula, lines, prevB);
|
||||||
|
materials.add(
|
||||||
|
createMotherRubberMaterial(
|
||||||
|
motherSpecCode,
|
||||||
|
motherWeight,
|
||||||
|
materials.size(),
|
||||||
|
formula,
|
||||||
|
compoundSpecificGravity,
|
||||||
|
categoryIdCache,
|
||||||
|
mixerCache,
|
||||||
|
categoryNameCache,
|
||||||
|
kindLookup));
|
||||||
|
appendBStageColumnAgents(lines, bColumn, materials, mixerCache, categoryNameCache, kindLookup);
|
||||||
|
reindexMaterialSortNo(materials);
|
||||||
|
return materials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 含 Q 时最后一段 B 的段号(如混合段3段则最后 B 为 B2) */
|
||||||
|
private int resolveLastBSegmentIndex(MesXslFormulaSpec formula, List<MesXslFormulaSpecLine> lines) {
|
||||||
|
int stageCount = normalizeMixingStages(formula != null ? formula.getMixingStages() : null);
|
||||||
|
if (stageCount <= 0 || !hasStepQ(lines)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return stageCount > 1 ? stageCount - 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** F 段本列:STEP=Q 且该列有数值的配合剂 */
|
||||||
|
private void appendQStageColumnAgents(
|
||||||
|
List<MesXslFormulaSpecLine> lines,
|
||||||
|
int column,
|
||||||
|
List<MesXslMixingSpecMaterial> materials,
|
||||||
|
Map<String, MesMixerMaterial> mixerCache,
|
||||||
|
Map<String, String> categoryNameCache,
|
||||||
|
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||||
|
for (MesXslFormulaSpecLine line : lines) {
|
||||||
|
if (!isLineStep(line, "Q")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BigDecimal unitWeight = readStageValue(line, column);
|
||||||
|
if (!hasStageNumericValue(unitWeight)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
materials.add(
|
||||||
|
toMixingMaterial(line, unitWeight, materials.size(), mixerCache, categoryNameCache, kindLookup));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 本段列:STEP=A 且该列有数值的配合剂 */
|
||||||
|
private void appendBStageColumnAgents(
|
||||||
|
List<MesXslFormulaSpecLine> lines,
|
||||||
|
int column,
|
||||||
|
List<MesXslMixingSpecMaterial> materials,
|
||||||
|
Map<String, MesMixerMaterial> mixerCache,
|
||||||
|
Map<String, String> categoryNameCache,
|
||||||
|
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||||
|
for (MesXslFormulaSpecLine line : lines) {
|
||||||
|
if (!isLineStep(line, "A")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BigDecimal unitWeight = resolveBColumnUnitWeight(line, column);
|
||||||
|
if (!hasStageNumericValue(unitWeight)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
materials.add(
|
||||||
|
toMixingMaterial(line, unitWeight, materials.size(), mixerCache, categoryNameCache, kindLookup));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A54】母炼胶明细行绑定已同步密炼物料主数据-----------
|
||||||
|
/**
|
||||||
|
* 上一段密炼产出胶料(一条):示方编号 B{n-1}+胶料名。
|
||||||
|
* 先确保对应密炼物料主数据存在,再按主数据回填明细(种类走配置表 + 小类 ID)。
|
||||||
|
*/
|
||||||
|
private MesXslMixingSpecMaterial createMotherRubberMaterial(
|
||||||
|
String motherSpecCode,
|
||||||
|
BigDecimal unitWeight,
|
||||||
|
int sortNo,
|
||||||
|
MesXslFormulaSpec formula,
|
||||||
|
BigDecimal compoundSpecificGravity,
|
||||||
|
Map<String, String> categoryIdCache,
|
||||||
|
Map<String, MesMixerMaterial> mixerCache,
|
||||||
|
Map<String, String> categoryNameCache,
|
||||||
|
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||||
|
ensureMotherRubberMixerMaterialSynced(motherSpecCode, formula, compoundSpecificGravity, categoryIdCache);
|
||||||
|
MesXslMixingSpecMaterial material = new MesXslMixingSpecMaterial();
|
||||||
|
material.setSortNo(sortNo);
|
||||||
|
material.setUnitWeight(unitWeight);
|
||||||
|
MesMixerMaterial mixer = findMixerMaterialByCodeOrName(motherSpecCode.trim());
|
||||||
|
if (mixer != null) {
|
||||||
|
fillMixingMaterialFromMixerMaterial(material, mixer, null, mixerCache, categoryNameCache, kindLookup);
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
log.warn("[混炼示方生成] 未找到上一段密炼物料 {},明细行回退为示方编号展示", motherSpecCode);
|
||||||
|
material.setMixerMaterialName(motherSpecCode);
|
||||||
|
material.setMixerMaterialDesc(motherSpecCode);
|
||||||
|
fillMotherRubberCategoryFallback(material, categoryIdCache, categoryNameCache, kindLookup);
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 上一段 B 段胶尚未写入主数据时,按母炼胶/A胶分类补建一条密炼物料 */
|
||||||
|
private void ensureMotherRubberMixerMaterialSynced(
|
||||||
|
String motherSpecCode,
|
||||||
|
MesXslFormulaSpec formula,
|
||||||
|
BigDecimal compoundSpecificGravity,
|
||||||
|
Map<String, String> categoryIdCache) {
|
||||||
|
if (StringUtils.isBlank(motherSpecCode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String normalized = motherSpecCode.trim();
|
||||||
|
if (findMixerMaterialByCodeOrName(normalized) != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MesXslFormulaMixingGenerateRowVO stub = new MesXslFormulaMixingGenerateRowVO();
|
||||||
|
stub.setSpecCode(normalized);
|
||||||
|
stub.setStepType("A");
|
||||||
|
syncGeneratedRubberMixerMaterial(stub, formula, compoundSpecificGravity, categoryIdCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 按密炼物料主数据回填混炼示方明细行(名称/大小类/种类) */
|
||||||
|
private void fillMixingMaterialFromMixerMaterial(
|
||||||
|
MesXslMixingSpecMaterial material,
|
||||||
|
MesMixerMaterial mixer,
|
||||||
|
String weighMode,
|
||||||
|
Map<String, MesMixerMaterial> mixerCache,
|
||||||
|
Map<String, String> categoryNameCache,
|
||||||
|
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||||
|
if (material == null || mixer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String displayName =
|
||||||
|
StringUtils.isNotBlank(mixer.getMaterialName()) ? mixer.getMaterialName() : mixer.getMaterialCode();
|
||||||
|
material.setMixerMaterialName(displayName);
|
||||||
|
material.setMixerMaterialDesc(
|
||||||
|
StringUtils.isNotBlank(mixer.getMaterialDesc()) ? mixer.getMaterialDesc() : displayName);
|
||||||
|
String majorName = resolveCategoryName(mixer.getMajorCategoryId(), categoryNameCache);
|
||||||
|
String minorName = resolveCategoryName(mixer.getMinorCategoryId(), categoryNameCache);
|
||||||
|
material.setMaterialMajor(majorName);
|
||||||
|
material.setMaterialMinor(minorName);
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A55】混炼示方明细回填密炼物料ID-----------
|
||||||
|
material.setMixerMaterialId(mixer.getId());
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A55】混炼示方明细回填密炼物料ID-----------
|
||||||
|
material.setMaterialKind(
|
||||||
|
mesXslMixerMaterialKindCfgService.resolveMixingMaterialKind(
|
||||||
|
kindLookup, mixer.getMinorCategoryId(), weighMode, minorName));
|
||||||
|
if (mixerCache != null && StringUtils.isNotBlank(mixer.getId())) {
|
||||||
|
mixerCache.put(mixer.getId(), mixer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 未查到密炼物料时,按母炼胶/A胶分类从配置表解析种类 */
|
||||||
|
private void fillMotherRubberCategoryFallback(
|
||||||
|
MesXslMixingSpecMaterial material,
|
||||||
|
Map<String, String> categoryIdCache,
|
||||||
|
Map<String, String> categoryNameCache,
|
||||||
|
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||||
|
String majorCategoryId = resolveCategoryIdByCode(CATEGORY_MASTER_MAJOR, categoryIdCache);
|
||||||
|
String minorCategoryId = resolveCategoryIdByCode(CATEGORY_MASTER_MINOR_A, categoryIdCache);
|
||||||
|
material.setMaterialMajor(resolveCategoryName(majorCategoryId, categoryNameCache));
|
||||||
|
material.setMaterialMinor(resolveCategoryName(minorCategoryId, categoryNameCache));
|
||||||
|
material.setMaterialKind(
|
||||||
|
mesXslMixerMaterialKindCfgService.resolveMixingMaterialKind(
|
||||||
|
kindLookup, minorCategoryId, null, material.getMaterialMinor()));
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A54】母炼胶明细行绑定已同步密炼物料主数据-----------
|
||||||
|
|
||||||
|
/** 混合段累计合计:优先主表 stageNTotal,否则按明细该列求和 */
|
||||||
|
private BigDecimal resolveStageCumulativeTotal(MesXslFormulaSpec formula, List<MesXslFormulaSpecLine> lines, int column) {
|
||||||
|
BigDecimal fromMain = readStageTotalFromMain(formula, column);
|
||||||
|
if (hasStageNumericValue(fromMain)) {
|
||||||
|
return fromMain;
|
||||||
|
}
|
||||||
|
BigDecimal sum = BigDecimal.ZERO;
|
||||||
|
boolean hasAny = false;
|
||||||
|
for (MesXslFormulaSpecLine line : lines) {
|
||||||
|
if (line == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BigDecimal w = readStageValue(line, column);
|
||||||
|
if (!hasStageNumericValue(w)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sum = sum.add(w);
|
||||||
|
hasAny = true;
|
||||||
|
}
|
||||||
|
return hasAny ? sum : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal readStageTotalFromMain(MesXslFormulaSpec formula, int column) {
|
||||||
|
if (formula == null || column < 1 || column > 7) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return switch (column) {
|
||||||
|
case 1 -> formula.getStage1Total();
|
||||||
|
case 2 -> formula.getStage2Total();
|
||||||
|
case 3 -> formula.getStage3Total();
|
||||||
|
case 4 -> formula.getStage4Total();
|
||||||
|
case 5 -> formula.getStage5Total();
|
||||||
|
case 6 -> formula.getStage6Total();
|
||||||
|
case 7 -> formula.getStage7Total();
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** B 段单重:优先取当前列;第1列 STEP=A 可回退 PHR */
|
||||||
|
private BigDecimal resolveBColumnUnitWeight(MesXslFormulaSpecLine line, int column) {
|
||||||
|
BigDecimal weight = readStageValue(line, column);
|
||||||
|
if (hasStageNumericValue(weight)) {
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
if (column == 1 && isLineStep(line, "A") && line.getPhr() != null) {
|
||||||
|
return line.getPhr();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reindexMaterialSortNo(List<MesXslMixingSpecMaterial> materials) {
|
||||||
|
for (int i = 0; i < materials.size(); i++) {
|
||||||
|
materials.get(i).setSortNo(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLineStep(MesXslFormulaSpecLine line, String step) {
|
||||||
|
if (line == null || StringUtils.isBlank(step)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String lineStep = StringUtils.isNotBlank(line.getStep()) ? line.getStep().trim().toUpperCase() : "";
|
||||||
|
return step.equalsIgnoreCase(lineStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 混合段列是否有有效数值(非空且非 0) */
|
||||||
|
private boolean hasStageNumericValue(BigDecimal value) {
|
||||||
|
return value != null && value.compareTo(BigDecimal.ZERO) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MesXslMixingSpecMaterial toMixingMaterial(
|
||||||
|
MesXslFormulaSpecLine line,
|
||||||
|
BigDecimal unitWeight,
|
||||||
|
int sortNo,
|
||||||
|
Map<String, MesMixerMaterial> mixerCache,
|
||||||
|
Map<String, String> categoryNameCache,
|
||||||
|
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||||
|
MesXslMixingSpecMaterial material = new MesXslMixingSpecMaterial();
|
||||||
|
material.setSortNo(sortNo);
|
||||||
|
material.setMixerMaterialName(line.getMixerMaterialName());
|
||||||
|
material.setMixerMaterialDesc(
|
||||||
|
StringUtils.isNotBlank(line.getMaterialDesc()) ? line.getMaterialDesc() : line.getMixerMaterialName());
|
||||||
|
material.setUnitWeight(unitWeight);
|
||||||
|
fillMaterialCategory(material, line.getMixerMaterialId(), line, mixerCache, categoryNameCache, kindLookup);
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillMaterialCategory(
|
||||||
|
MesXslMixingSpecMaterial material,
|
||||||
|
String mixerMaterialId,
|
||||||
|
MesXslFormulaSpecLine line,
|
||||||
|
Map<String, MesMixerMaterial> mixerCache,
|
||||||
|
Map<String, String> categoryNameCache,
|
||||||
|
MesXslMixerMaterialKindLookupVO kindLookup) {
|
||||||
|
if (oConvertUtils.isEmpty(mixerMaterialId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MesMixerMaterial mixer = mixerCache.computeIfAbsent(mixerMaterialId, id -> mesMixerMaterialService.getById(id));
|
||||||
|
if (mixer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String weighMode = line != null ? line.getWeighMode() : null;
|
||||||
|
fillMixingMaterialFromMixerMaterial(material, mixer, weighMode, mixerCache, categoryNameCache, kindLookup);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal readStageValue(MesXslFormulaSpecLine line, int stageIndex) {
|
||||||
|
if (line == null || stageIndex < 1 || stageIndex > 7) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return switch (stageIndex) {
|
||||||
|
case 1 -> line.getStage1();
|
||||||
|
case 2 -> line.getStage2();
|
||||||
|
case 3 -> line.getStage3();
|
||||||
|
case 4 -> line.getStage4();
|
||||||
|
case 5 -> line.getStage5();
|
||||||
|
case 6 -> line.getStage6();
|
||||||
|
case 7 -> line.getStage7();
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveCategoryName(String categoryId, Map<String, String> cache) {
|
||||||
|
if (oConvertUtils.isEmpty(categoryId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return cache.computeIfAbsent(categoryId, id -> {
|
||||||
|
SysCategory category = sysCategoryService.getById(id);
|
||||||
|
return category != null ? category.getName() : null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方预览与批量创建-----------
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,406 @@
|
|||||||
|
package org.jeecg.modules.xslmes.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
|
import org.jeecg.common.util.TokenUtils;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.common.config.TenantContext;
|
||||||
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
|
import org.jeecg.modules.system.entity.SysCategory;
|
||||||
|
import org.jeecg.modules.system.entity.SysDict;
|
||||||
|
import org.jeecg.modules.system.entity.SysDictItem;
|
||||||
|
import org.jeecg.modules.system.service.ISysCategoryService;
|
||||||
|
import org.jeecg.modules.system.service.ISysDictItemService;
|
||||||
|
import org.jeecg.modules.system.service.ISysDictService;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixerMaterialKindCfg;
|
||||||
|
import org.jeecg.modules.xslmes.mapper.MesXslMixerMaterialKindCfgMapper;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslMixerMaterialKindCfgService;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslMixerMaterialKindLookupVO;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES 密炼物料种类配置
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MesXslMixerMaterialKindCfgServiceImpl
|
||||||
|
extends ServiceImpl<MesXslMixerMaterialKindCfgMapper, MesXslMixerMaterialKindCfg>
|
||||||
|
implements IMesXslMixerMaterialKindCfgService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysDictService sysDictService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysDictItemService sysDictItemService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysCategoryService sysCategoryService;
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存-----------
|
||||||
|
@Override
|
||||||
|
public List<MesXslMixerMaterialKindCfg> expandLines(String sourceType, String sourceRootCode, Integer tenantId) {
|
||||||
|
if (oConvertUtils.isEmpty(sourceType) || oConvertUtils.isEmpty(sourceRootCode)) {
|
||||||
|
throw new JeecgBootException("请选择数据源类型与根字典/分类");
|
||||||
|
}
|
||||||
|
String normalizedType = sourceType.trim().toLowerCase();
|
||||||
|
String rootCode = sourceRootCode.trim();
|
||||||
|
if (MesXslMixerMaterialKindCfg.SOURCE_TYPE_DICT.equals(normalizedType)) {
|
||||||
|
return expandFromDict(rootCode, tenantId);
|
||||||
|
}
|
||||||
|
if (MesXslMixerMaterialKindCfg.SOURCE_TYPE_CATEGORY.equals(normalizedType)) {
|
||||||
|
return expandFromCategory(rootCode, tenantId);
|
||||||
|
}
|
||||||
|
throw new JeecgBootException("不支持的数据源类型:" + sourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void saveBatchLines(List<MesXslMixerMaterialKindCfg> lines, Integer tenantId) {
|
||||||
|
if (lines == null || lines.isEmpty()) {
|
||||||
|
throw new JeecgBootException("请至少维护一条种类配置明细");
|
||||||
|
}
|
||||||
|
Integer resolvedTenantId = resolveTenantId(tenantId);
|
||||||
|
Set<String> kindKeys = new HashSet<>();
|
||||||
|
Set<String> categoryRefIds = new HashSet<>();
|
||||||
|
for (MesXslMixerMaterialKindCfg line : lines) {
|
||||||
|
String err = validateLine(line, kindKeys, categoryRefIds);
|
||||||
|
if (err != null) {
|
||||||
|
throw new JeecgBootException(err);
|
||||||
|
}
|
||||||
|
line.setTenantId(resolvedTenantId);
|
||||||
|
line.setDelFlag(CommonConstant.DEL_FLAG_0);
|
||||||
|
checkDuplicate(line, null);
|
||||||
|
}
|
||||||
|
saveBatch(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MesXslMixerMaterialKindCfg> expandFromDict(String dictCode, Integer tenantId) {
|
||||||
|
LambdaQueryWrapper<SysDict> dictQw = new LambdaQueryWrapper<>();
|
||||||
|
dictQw.eq(SysDict::getDictCode, dictCode);
|
||||||
|
SysDict dict = sysDictService.getOne(dictQw, false);
|
||||||
|
if (dict == null) {
|
||||||
|
throw new JeecgBootException("数据字典不存在:" + dictCode);
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<SysDictItem> itemQw = new LambdaQueryWrapper<>();
|
||||||
|
itemQw.eq(SysDictItem::getDictId, dict.getId());
|
||||||
|
itemQw.eq(SysDictItem::getStatus, 1);
|
||||||
|
itemQw.orderByAsc(SysDictItem::getSortOrder).orderByAsc(SysDictItem::getItemValue);
|
||||||
|
List<SysDictItem> items = sysDictItemService.list(itemQw);
|
||||||
|
if (items == null || items.isEmpty()) {
|
||||||
|
throw new JeecgBootException("该数据字典下没有可用的字典项");
|
||||||
|
}
|
||||||
|
Set<String> existsRefIds = loadExistingCategoryRefIds(MesXslMixerMaterialKindCfg.SOURCE_TYPE_DICT, dictCode, tenantId);
|
||||||
|
List<MesXslMixerMaterialKindCfg> result = new ArrayList<>();
|
||||||
|
int priorityBase = 10;
|
||||||
|
int index = 0;
|
||||||
|
for (SysDictItem item : items) {
|
||||||
|
if (item == null || oConvertUtils.isEmpty(item.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (existsRefIds.contains(item.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
MesXslMixerMaterialKindCfg cfg = new MesXslMixerMaterialKindCfg();
|
||||||
|
cfg.setSourceType(MesXslMixerMaterialKindCfg.SOURCE_TYPE_DICT);
|
||||||
|
cfg.setSourceRootCode(dictCode);
|
||||||
|
cfg.setSourceRootName(dict.getDictName());
|
||||||
|
cfg.setCategoryRefId(item.getId());
|
||||||
|
cfg.setCategoryRefCode(item.getItemValue());
|
||||||
|
cfg.setCategoryRefName(item.getItemText());
|
||||||
|
cfg.setKindKey(item.getItemValue());
|
||||||
|
cfg.setKindName(item.getItemText());
|
||||||
|
cfg.setPriority(item.getSortOrder() != null ? item.getSortOrder() : priorityBase + index * 10);
|
||||||
|
cfg.setTenantId(resolveTenantId(tenantId));
|
||||||
|
result.add(cfg);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
throw new JeecgBootException("该数据字典下的字典项均已配置,无需重复带出");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MesXslMixerMaterialKindCfg> expandFromCategory(String rootCode, Integer tenantId) {
|
||||||
|
LambdaQueryWrapper<SysCategory> rootQw = new LambdaQueryWrapper<>();
|
||||||
|
rootQw.eq(SysCategory::getCode, rootCode);
|
||||||
|
SysCategory root = sysCategoryService.getOne(rootQw, false);
|
||||||
|
if (root == null) {
|
||||||
|
throw new JeecgBootException("分类字典不存在:" + rootCode);
|
||||||
|
}
|
||||||
|
List<SysCategory> descendants = new ArrayList<>();
|
||||||
|
Deque<String> queue = new ArrayDeque<>();
|
||||||
|
queue.add(root.getId());
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
String parentId = queue.poll();
|
||||||
|
LambdaQueryWrapper<SysCategory> childQw = new LambdaQueryWrapper<>();
|
||||||
|
childQw.eq(SysCategory::getPid, parentId);
|
||||||
|
childQw.orderByAsc(SysCategory::getCode);
|
||||||
|
List<SysCategory> children = sysCategoryService.list(childQw);
|
||||||
|
if (children == null || children.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (SysCategory child : children) {
|
||||||
|
descendants.add(child);
|
||||||
|
queue.add(child.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (descendants.isEmpty()) {
|
||||||
|
throw new JeecgBootException("该分类下没有可用的子分类");
|
||||||
|
}
|
||||||
|
Set<String> existsRefIds = loadExistingCategoryRefIds(MesXslMixerMaterialKindCfg.SOURCE_TYPE_CATEGORY, rootCode, tenantId);
|
||||||
|
List<MesXslMixerMaterialKindCfg> result = new ArrayList<>();
|
||||||
|
int priorityBase = 10;
|
||||||
|
for (int i = 0; i < descendants.size(); i++) {
|
||||||
|
SysCategory category = descendants.get(i);
|
||||||
|
if (category == null || oConvertUtils.isEmpty(category.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (existsRefIds.contains(category.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String refCode = oConvertUtils.isNotEmpty(category.getCode()) ? category.getCode() : category.getId();
|
||||||
|
MesXslMixerMaterialKindCfg cfg = new MesXslMixerMaterialKindCfg();
|
||||||
|
cfg.setSourceType(MesXslMixerMaterialKindCfg.SOURCE_TYPE_CATEGORY);
|
||||||
|
cfg.setSourceRootCode(rootCode);
|
||||||
|
cfg.setSourceRootName(root.getName());
|
||||||
|
cfg.setCategoryRefId(category.getId());
|
||||||
|
cfg.setCategoryRefCode(refCode);
|
||||||
|
cfg.setCategoryRefName(category.getName());
|
||||||
|
cfg.setKindKey(refCode);
|
||||||
|
cfg.setKindName(category.getName());
|
||||||
|
cfg.setPriority(priorityBase + i * 10);
|
||||||
|
cfg.setTenantId(resolveTenantId(tenantId));
|
||||||
|
result.add(cfg);
|
||||||
|
}
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
throw new JeecgBootException("该分类下的子分类均已配置,无需重复带出");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> loadExistingCategoryRefIds(String sourceType, String sourceRootCode, Integer tenantId) {
|
||||||
|
LambdaQueryWrapper<MesXslMixerMaterialKindCfg> qw = new LambdaQueryWrapper<>();
|
||||||
|
qw.eq(MesXslMixerMaterialKindCfg::getSourceType, sourceType);
|
||||||
|
qw.eq(MesXslMixerMaterialKindCfg::getSourceRootCode, sourceRootCode);
|
||||||
|
qw.and(q -> q.eq(MesXslMixerMaterialKindCfg::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesXslMixerMaterialKindCfg::getDelFlag));
|
||||||
|
Integer resolvedTenantId = resolveTenantId(tenantId);
|
||||||
|
if (resolvedTenantId != null && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||||
|
qw.eq(MesXslMixerMaterialKindCfg::getTenantId, resolvedTenantId);
|
||||||
|
}
|
||||||
|
qw.select(MesXslMixerMaterialKindCfg::getCategoryRefId);
|
||||||
|
List<MesXslMixerMaterialKindCfg> exists = list(qw);
|
||||||
|
Set<String> ids = new HashSet<>();
|
||||||
|
if (exists != null) {
|
||||||
|
for (MesXslMixerMaterialKindCfg row : exists) {
|
||||||
|
if (row != null && oConvertUtils.isNotEmpty(row.getCategoryRefId())) {
|
||||||
|
ids.add(row.getCategoryRefId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String validateLine(MesXslMixerMaterialKindCfg line, Set<String> kindKeys, Set<String> categoryRefIds) {
|
||||||
|
if (line == null) {
|
||||||
|
return "存在空的明细行";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(line.getKindKey())) {
|
||||||
|
return "种类键值不能为空";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(line.getKindName())) {
|
||||||
|
return "种类名称不能为空";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(line.getSourceType())) {
|
||||||
|
return "数据源类型不能为空";
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(line.getCategoryRefId())) {
|
||||||
|
return "对应分类不能为空";
|
||||||
|
}
|
||||||
|
String kindKey = line.getKindKey().trim();
|
||||||
|
if (!kindKeys.add(kindKey)) {
|
||||||
|
return "本次提交存在重复的种类键值:" + kindKey;
|
||||||
|
}
|
||||||
|
String refId = line.getCategoryRefId().trim();
|
||||||
|
if (!categoryRefIds.add(refId)) {
|
||||||
|
return "本次提交存在重复的对应分类";
|
||||||
|
}
|
||||||
|
if (line.getPriority() == null) {
|
||||||
|
line.setPriority(999);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkDuplicate(MesXslMixerMaterialKindCfg line, String excludeId) {
|
||||||
|
Integer tenantId = resolveTenantId(line.getTenantId());
|
||||||
|
LambdaQueryWrapper<MesXslMixerMaterialKindCfg> kindQw = new LambdaQueryWrapper<>();
|
||||||
|
kindQw.eq(MesXslMixerMaterialKindCfg::getKindKey, line.getKindKey().trim());
|
||||||
|
kindQw.and(q -> q.eq(MesXslMixerMaterialKindCfg::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesXslMixerMaterialKindCfg::getDelFlag));
|
||||||
|
if (tenantId != null && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||||
|
kindQw.eq(MesXslMixerMaterialKindCfg::getTenantId, tenantId);
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isNotEmpty(excludeId)) {
|
||||||
|
kindQw.ne(MesXslMixerMaterialKindCfg::getId, excludeId);
|
||||||
|
}
|
||||||
|
if (count(kindQw) > 0) {
|
||||||
|
throw new JeecgBootException("种类键值已存在:" + line.getKindKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaQueryWrapper<MesXslMixerMaterialKindCfg> refQw = new LambdaQueryWrapper<>();
|
||||||
|
refQw.eq(MesXslMixerMaterialKindCfg::getCategoryRefId, line.getCategoryRefId().trim());
|
||||||
|
refQw.and(q -> q.eq(MesXslMixerMaterialKindCfg::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesXslMixerMaterialKindCfg::getDelFlag));
|
||||||
|
if (tenantId != null && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||||
|
refQw.eq(MesXslMixerMaterialKindCfg::getTenantId, tenantId);
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isNotEmpty(excludeId)) {
|
||||||
|
refQw.ne(MesXslMixerMaterialKindCfg::getId, excludeId);
|
||||||
|
}
|
||||||
|
if (count(refQw) > 0) {
|
||||||
|
throw new JeecgBootException("对应分类已配置:" + line.getCategoryRefName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Integer resolveTenantId(Integer tenantId) {
|
||||||
|
if (tenantId != null) {
|
||||||
|
return tenantId;
|
||||||
|
}
|
||||||
|
String ts = TenantContext.getTenant();
|
||||||
|
if (oConvertUtils.isEmpty(ts)) {
|
||||||
|
try {
|
||||||
|
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
|
||||||
|
if (request != null) {
|
||||||
|
ts = TokenUtils.getTenantIdByRequest(request);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(ts)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(ts);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A51】密炼物料种类配置展开与批量保存-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||||
|
private static final String DEFAULT_RUBBER_KIND_NAME = "胶料";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MesXslMixerMaterialKindLookupVO loadKindLookup(Integer tenantId) {
|
||||||
|
LambdaQueryWrapper<MesXslMixerMaterialKindCfg> qw = new LambdaQueryWrapper<>();
|
||||||
|
qw.and(q -> q.eq(MesXslMixerMaterialKindCfg::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesXslMixerMaterialKindCfg::getDelFlag));
|
||||||
|
Integer resolvedTenantId = resolveTenantId(tenantId);
|
||||||
|
if (resolvedTenantId != null && MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||||
|
qw.eq(MesXslMixerMaterialKindCfg::getTenantId, resolvedTenantId);
|
||||||
|
}
|
||||||
|
qw.orderByAsc(MesXslMixerMaterialKindCfg::getPriority).orderByAsc(MesXslMixerMaterialKindCfg::getKindKey);
|
||||||
|
List<MesXslMixerMaterialKindCfg> rows = list(qw);
|
||||||
|
|
||||||
|
MesXslMixerMaterialKindLookupVO lookup = new MesXslMixerMaterialKindLookupVO();
|
||||||
|
Map<String, String> byRefId = new LinkedHashMap<>();
|
||||||
|
Map<String, String> byRefCode = new LinkedHashMap<>();
|
||||||
|
String rubberKindName = null;
|
||||||
|
if (rows != null) {
|
||||||
|
for (MesXslMixerMaterialKindCfg row : rows) {
|
||||||
|
if (row == null || oConvertUtils.isEmpty(row.getKindName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String kindName = row.getKindName().trim();
|
||||||
|
if (oConvertUtils.isNotEmpty(row.getCategoryRefId()) && !byRefId.containsKey(row.getCategoryRefId().trim())) {
|
||||||
|
byRefId.put(row.getCategoryRefId().trim(), kindName);
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isNotEmpty(row.getCategoryRefCode())) {
|
||||||
|
String refCode = row.getCategoryRefCode().trim();
|
||||||
|
if (!byRefCode.containsKey(refCode)) {
|
||||||
|
byRefCode.put(refCode, kindName);
|
||||||
|
}
|
||||||
|
String lowerCode = refCode.toLowerCase();
|
||||||
|
if (!lowerCode.equals(refCode) && !byRefCode.containsKey(lowerCode)) {
|
||||||
|
byRefCode.put(lowerCode, kindName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rubberKindName == null && DEFAULT_RUBBER_KIND_NAME.equals(kindName)) {
|
||||||
|
rubberKindName = kindName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lookup.setByRefId(byRefId);
|
||||||
|
lookup.setByRefCode(byRefCode);
|
||||||
|
lookup.setRubberKindName(oConvertUtils.isNotEmpty(rubberKindName) ? rubberKindName : DEFAULT_RUBBER_KIND_NAME);
|
||||||
|
return lookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resolveMixingMaterialKind(
|
||||||
|
MesXslMixerMaterialKindLookupVO lookup,
|
||||||
|
String minorCategoryId,
|
||||||
|
String weighMode,
|
||||||
|
String minorCategoryName) {
|
||||||
|
if (lookup == null) {
|
||||||
|
lookup = loadKindLookup(null);
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isNotEmpty(weighMode)) {
|
||||||
|
String fromWeighMode = matchKindFromLookup(lookup, weighMode.trim());
|
||||||
|
if (oConvertUtils.isNotEmpty(fromWeighMode)) {
|
||||||
|
return fromWeighMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isNotEmpty(minorCategoryId)) {
|
||||||
|
String fromMinor = matchKindFromLookup(lookup, minorCategoryId.trim());
|
||||||
|
if (oConvertUtils.isNotEmpty(fromMinor)) {
|
||||||
|
return fromMinor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】种类未命中配置时不回退小类名-----------
|
||||||
|
return null;
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】种类未命中配置时不回退小类名-----------
|
||||||
|
}
|
||||||
|
|
||||||
|
private String matchKindFromLookup(MesXslMixerMaterialKindLookupVO lookup, String key) {
|
||||||
|
if (lookup == null || oConvertUtils.isEmpty(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Map<String, String> byRefId = lookup.getByRefId();
|
||||||
|
if (byRefId != null && byRefId.containsKey(key)) {
|
||||||
|
return byRefId.get(key);
|
||||||
|
}
|
||||||
|
Map<String, String> byRefCode = lookup.getByRefCode();
|
||||||
|
if (byRefCode == null || byRefCode.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (byRefCode.containsKey(key)) {
|
||||||
|
return byRefCode.get(key);
|
||||||
|
}
|
||||||
|
String lower = key.toLowerCase();
|
||||||
|
if (byRefCode.containsKey(lower)) {
|
||||||
|
return byRefCode.get(lower);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(key)) {
|
||||||
|
for (Map.Entry<String, String> entry : byRefCode.entrySet()) {
|
||||||
|
if (entry.getKey() != null && key.contains(entry.getKey())) {
|
||||||
|
return entry.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】密炼物料种类配置关联解析-----------
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import org.jeecg.common.util.oConvertUtils;
|
|||||||
import org.jeecg.modules.xslmes.common.XslMesBizConstants;
|
import org.jeecg.modules.xslmes.common.XslMesBizConstants;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile;
|
import org.jeecg.modules.xslmes.entity.MesXslMixerPsCompile;
|
||||||
import org.jeecg.modules.xslmes.mapper.MesXslMixerPsCompileMapper;
|
import org.jeecg.modules.xslmes.mapper.MesXslMixerPsCompileMapper;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslFormulaSpecService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService;
|
import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
|
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -22,6 +23,9 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
public class MesXslMixerPsCompileServiceImpl extends ServiceImpl<MesXslMixerPsCompileMapper, MesXslMixerPsCompile>
|
public class MesXslMixerPsCompileServiceImpl extends ServiceImpl<MesXslMixerPsCompileMapper, MesXslMixerPsCompile>
|
||||||
implements IMesXslMixerPsCompileService {
|
implements IMesXslMixerPsCompileService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslFormulaSpecService mesXslFormulaSpecService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslRubberQuickTestStdService mesXslRubberQuickTestStdService;
|
private IMesXslRubberQuickTestStdService mesXslRubberQuickTestStdService;
|
||||||
|
|
||||||
@@ -54,6 +58,9 @@ public class MesXslMixerPsCompileServiceImpl extends ServiceImpl<MesXslMixerPsCo
|
|||||||
entity.setStatus(targetStatus);
|
entity.setStatus(targetStatus);
|
||||||
fillWorkflowInfo(entity, targetStatus, operatorName, now);
|
fillWorkflowInfo(entity, targetStatus, operatorName, now);
|
||||||
updateById(entity);
|
updateById(entity);
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人-----------
|
||||||
|
mesXslFormulaSpecService.syncFromMixerPsWorkflow(entity, targetStatus);
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【配合示方】密炼PS审批联动同步状态与审批人-----------
|
||||||
//update-begin---author:jiangxh ---date:20260525 for:【MES】原材料检验标准PS批准后关联实验标准置已批准-----------
|
//update-begin---author:jiangxh ---date:20260525 for:【MES】原材料检验标准PS批准后关联实验标准置已批准-----------
|
||||||
if ("approve".equals(targetStatus)
|
if ("approve".equals(targetStatus)
|
||||||
&& XslMesBizConstants.PS_TYPE_RAW_INSPECT_STD.equals(entity.getPsType())) {
|
&& XslMesBizConstants.PS_TYPE_RAW_INSPECT_STD.equals(entity.getPsType())) {
|
||||||
|
|||||||
@@ -0,0 +1,785 @@
|
|||||||
|
package org.jeecg.modules.xslmes.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.baomidou.mybatisplus.extension.toolkit.Db;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
import org.jeecg.modules.mes.material.entity.MesMixerMaterial;
|
||||||
|
import org.jeecg.modules.mes.material.service.IMesMixerMaterialService;
|
||||||
|
import org.jeecg.modules.system.entity.SysCategory;
|
||||||
|
import org.jeecg.modules.system.service.ISysCategoryService;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecStep;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecTcu;
|
||||||
|
import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecDownStepMapper;
|
||||||
|
import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecMapper;
|
||||||
|
import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecMaterialMapper;
|
||||||
|
import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecStepMapper;
|
||||||
|
import org.jeecg.modules.xslmes.mapper.MesXslMixingSpecTcuMapper;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class MesXslMixingSpecServiceImpl extends ServiceImpl<MesXslMixingSpecMapper, MesXslMixingSpec>
|
||||||
|
implements IMesXslMixingSpecService {
|
||||||
|
|
||||||
|
private static final String TCU_UP = "up_mixer";
|
||||||
|
private static final String TCU_DOWN = "down_mixer";
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料-----------
|
||||||
|
private static final String CATEGORY_MASTER_MAJOR = "XSLMES_MATERIAL_MASTER";
|
||||||
|
private static final String CATEGORY_MASTER_MINOR_A = "XSLMES_MATERIAL_MASTER_A";
|
||||||
|
private static final String CATEGORY_FINAL_MAJOR = "XSLMES_MATERIAL_FINAL";
|
||||||
|
private static final String CATEGORY_FINAL_MINOR_Q = "XSLMES_MATERIAL_FINAL_Q";
|
||||||
|
private static final Pattern GENERATED_B_RUBBER_SPEC_PATTERN = Pattern.compile("^B\\d", Pattern.CASE_INSENSITIVE);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料-----------
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MesXslMixingSpecMaterialMapper materialMapper;
|
||||||
|
@Resource
|
||||||
|
private MesXslMixingSpecStepMapper stepMapper;
|
||||||
|
@Resource
|
||||||
|
private MesXslMixingSpecDownStepMapper downStepMapper;
|
||||||
|
@Resource
|
||||||
|
private MesXslMixingSpecTcuMapper tcuMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IMesMixerMaterialService mesMixerMaterialService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ISysCategoryService sysCategoryService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void saveMain(
|
||||||
|
MesXslMixingSpec main,
|
||||||
|
List<MesXslMixingSpecMaterial> materialList,
|
||||||
|
List<MesXslMixingSpecStep> stepList,
|
||||||
|
List<MesXslMixingSpecDownStep> downStepList,
|
||||||
|
List<MesXslMixingSpecTcu> tcuList) {
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
SavePerfTrace trace = new SavePerfTrace("新增", main);
|
||||||
|
trace.logPayloadSize(materialList, stepList, downStepList, tcuList);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表新增保存-----------
|
||||||
|
normalizeMain(main);
|
||||||
|
trace.step("normalizeMain");
|
||||||
|
this.save(main);
|
||||||
|
trace.step("saveMain", "mainId", main.getId());
|
||||||
|
saveChildren(main.getId(), materialList, stepList, downStepList, tcuList, trace);
|
||||||
|
trace.finish();
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表新增保存-----------
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateMain(
|
||||||
|
MesXslMixingSpec main,
|
||||||
|
List<MesXslMixingSpecMaterial> materialList,
|
||||||
|
List<MesXslMixingSpecStep> stepList,
|
||||||
|
List<MesXslMixingSpecDownStep> downStepList,
|
||||||
|
List<MesXslMixingSpecTcu> tcuList) {
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
SavePerfTrace trace = new SavePerfTrace("编辑", main);
|
||||||
|
trace.logPayloadSize(materialList, stepList, downStepList, tcuList);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表编辑保存-----------
|
||||||
|
normalizeMain(main);
|
||||||
|
trace.step("normalizeMain");
|
||||||
|
this.updateById(main);
|
||||||
|
trace.step("updateMain");
|
||||||
|
clearChildren(main.getId(), trace);
|
||||||
|
saveChildren(main.getId(), materialList, stepList, downStepList, tcuList, trace);
|
||||||
|
trace.finish();
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】混炼示方主子表编辑保存-----------
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void delMain(String id) {
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A56】混炼示方批量删除性能优化-----------
|
||||||
|
if (StringUtils.isBlank(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delBatchMain(Collections.singletonList(id));
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A56】混炼示方批量删除性能优化-----------
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void delBatchMain(Collection<? extends Serializable> idList) {
|
||||||
|
if (CollectionUtils.isEmpty(idList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A56】混炼示方批量删除性能优化-----------
|
||||||
|
List<String> ids = idList.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(String::valueOf)
|
||||||
|
.filter(StringUtils::isNotBlank)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (ids.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<MesXslMixingSpec> mains = this.listByIds(ids);
|
||||||
|
if (CollectionUtils.isEmpty(mains)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clearChildrenBatch(ids);
|
||||||
|
this.removeByIds(ids);
|
||||||
|
Set<String> specNames = new LinkedHashSet<>();
|
||||||
|
for (MesXslMixingSpec main : mains) {
|
||||||
|
if (main != null && StringUtils.isNotBlank(main.getSpecName())) {
|
||||||
|
specNames.add(main.getSpecName().trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String specName : specNames) {
|
||||||
|
syncDeleteGeneratedRubberMixerMaterial(specName);
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A56】混炼示方批量删除性能优化-----------
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MesXslMixingSpecPage queryPageById(String id) {
|
||||||
|
MesXslMixingSpec main = this.getById(id);
|
||||||
|
if (main == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
MesXslMixingSpecPage page = new MesXslMixingSpecPage();
|
||||||
|
page.setId(main.getId());
|
||||||
|
page.setTenantId(main.getTenantId());
|
||||||
|
page.setSpecName(main.getSpecName());
|
||||||
|
page.setPurpose(main.getPurpose());
|
||||||
|
page.setMachineId(main.getMachineId());
|
||||||
|
page.setMachineName(main.getMachineName());
|
||||||
|
page.setMakeDate(main.getMakeDate());
|
||||||
|
page.setIssueNumber(main.getIssueNumber());
|
||||||
|
page.setConvertFactor(main.getConvertFactor());
|
||||||
|
page.setFillVolume(main.getFillVolume());
|
||||||
|
page.setRecycleCarbonSec(main.getRecycleCarbonSec());
|
||||||
|
page.setMotherRubberSg(main.getMotherRubberSg());
|
||||||
|
page.setFinalRubberSg(main.getFinalRubberSg());
|
||||||
|
page.setApplyFactory(main.getApplyFactory());
|
||||||
|
page.setStageCount(main.getStageCount());
|
||||||
|
page.setPureMixSec(main.getPureMixSec());
|
||||||
|
page.setRecycleCarbonKg(main.getRecycleCarbonKg());
|
||||||
|
page.setAutoSmallPrintSetting(main.getAutoSmallPrintSetting());
|
||||||
|
page.setSetTrainCount(main.getSetTrainCount());
|
||||||
|
page.setSideWallWaterTemp(main.getSideWallWaterTemp());
|
||||||
|
page.setOvertimeDischargeSec(main.getOvertimeDischargeSec());
|
||||||
|
page.setOvertempDischargeSec(main.getOvertempDischargeSec());
|
||||||
|
page.setOvertempDischargeTemp(main.getOvertempDischargeTemp());
|
||||||
|
page.setDoorWaterTemp(main.getDoorWaterTemp());
|
||||||
|
page.setRotorWaterTemp(main.getRotorWaterTemp());
|
||||||
|
page.setMaxFeedTemp(main.getMaxFeedTemp());
|
||||||
|
page.setDraftBy(main.getDraftBy());
|
||||||
|
page.setDraftTime(main.getDraftTime());
|
||||||
|
page.setProofreadBy(main.getProofreadBy());
|
||||||
|
page.setProofreadTime(main.getProofreadTime());
|
||||||
|
page.setAuditBy(main.getAuditBy());
|
||||||
|
page.setAuditTime(main.getAuditTime());
|
||||||
|
page.setApproveBy(main.getApproveBy());
|
||||||
|
page.setApproveTime(main.getApproveTime());
|
||||||
|
page.setChangeDate(main.getChangeDate());
|
||||||
|
page.setSysOrgCode(main.getSysOrgCode());
|
||||||
|
page.setCreateBy(main.getCreateBy());
|
||||||
|
page.setCreateTime(main.getCreateTime());
|
||||||
|
page.setUpdateBy(main.getUpdateBy());
|
||||||
|
page.setUpdateTime(main.getUpdateTime());
|
||||||
|
page.setDelFlag(main.getDelFlag());
|
||||||
|
|
||||||
|
page.setMaterialList(queryMaterialByMainId(id));
|
||||||
|
page.setStepList(queryStepByMainId(id));
|
||||||
|
page.setDownStepList(queryDownStepByMainId(id));
|
||||||
|
page.setTcuList(fillDefaultTcuRows(queryTcuByMainId(id)));
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, String>> queryIssueNumberOptions(String keyword) {
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】发行编号联想取密炼PS-----------
|
||||||
|
LambdaQueryWrapper<MesXslMixingSpec> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
if (StringUtils.isNotBlank(keyword)) {
|
||||||
|
queryWrapper.like(MesXslMixingSpec::getIssueNumber, keyword);
|
||||||
|
}
|
||||||
|
queryWrapper.isNotNull(MesXslMixingSpec::getIssueNumber)
|
||||||
|
.orderByDesc(MesXslMixingSpec::getUpdateTime)
|
||||||
|
.orderByDesc(MesXslMixingSpec::getCreateTime)
|
||||||
|
.last("limit 30");
|
||||||
|
List<MesXslMixingSpec> rows = this.list(queryWrapper);
|
||||||
|
List<Map<String, String>> options = new ArrayList<>();
|
||||||
|
for (MesXslMixingSpec row : rows) {
|
||||||
|
if (StringUtils.isBlank(row.getIssueNumber())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
options.add(Map.of("label", row.getIssueNumber(), "value", row.getIssueNumber()));
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A17】发行编号联想取密炼PS-----------
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, String>> queryPurposeOptions(String keyword) {
|
||||||
|
LambdaQueryWrapper<MesXslMixingSpec> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
if (StringUtils.isNotBlank(keyword)) {
|
||||||
|
queryWrapper.like(MesXslMixingSpec::getPurpose, keyword);
|
||||||
|
}
|
||||||
|
queryWrapper.isNotNull(MesXslMixingSpec::getPurpose)
|
||||||
|
.orderByDesc(MesXslMixingSpec::getUpdateTime)
|
||||||
|
.orderByDesc(MesXslMixingSpec::getCreateTime)
|
||||||
|
.last("limit 50");
|
||||||
|
List<MesXslMixingSpec> rows = this.list(queryWrapper);
|
||||||
|
List<Map<String, String>> options = new ArrayList<>();
|
||||||
|
for (MesXslMixingSpec row : rows) {
|
||||||
|
if (StringUtils.isBlank(row.getPurpose())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
options.add(Map.of("label", row.getPurpose(), "value", row.getPurpose()));
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void normalizeMain(MesXslMixingSpec main) {
|
||||||
|
if (main.getDraftTime() == null) {
|
||||||
|
main.setDraftTime(new Date());
|
||||||
|
}
|
||||||
|
if (main.getDelFlag() == null) {
|
||||||
|
main.setDelFlag(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearChildren(String mainId) {
|
||||||
|
clearChildren(mainId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearChildren(String mainId, SavePerfTrace trace) {
|
||||||
|
materialMapper.delete(new LambdaQueryWrapper<MesXslMixingSpecMaterial>().eq(MesXslMixingSpecMaterial::getMixingSpecId, mainId));
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("deleteMaterialChildren");
|
||||||
|
}
|
||||||
|
stepMapper.delete(new LambdaQueryWrapper<MesXslMixingSpecStep>().eq(MesXslMixingSpecStep::getMixingSpecId, mainId));
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("deleteStepChildren");
|
||||||
|
}
|
||||||
|
downStepMapper.delete(new LambdaQueryWrapper<MesXslMixingSpecDownStep>().eq(MesXslMixingSpecDownStep::getMixingSpecId, mainId));
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("deleteDownStepChildren");
|
||||||
|
}
|
||||||
|
tcuMapper.delete(new LambdaQueryWrapper<MesXslMixingSpecTcu>().eq(MesXslMixingSpecTcu::getMixingSpecId, mainId));
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("deleteTcuChildren");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A56】混炼示方批量删除性能优化-----------
|
||||||
|
/** 批量删除多个混炼示方的全部子表数据 */
|
||||||
|
private void clearChildrenBatch(Collection<String> mainIds) {
|
||||||
|
if (CollectionUtils.isEmpty(mainIds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
materialMapper.delete(new LambdaQueryWrapper<MesXslMixingSpecMaterial>().in(MesXslMixingSpecMaterial::getMixingSpecId, mainIds));
|
||||||
|
stepMapper.delete(new LambdaQueryWrapper<MesXslMixingSpecStep>().in(MesXslMixingSpecStep::getMixingSpecId, mainIds));
|
||||||
|
downStepMapper.delete(new LambdaQueryWrapper<MesXslMixingSpecDownStep>().in(MesXslMixingSpecDownStep::getMixingSpecId, mainIds));
|
||||||
|
tcuMapper.delete(new LambdaQueryWrapper<MesXslMixingSpecTcu>().in(MesXslMixingSpecTcu::getMixingSpecId, mainIds));
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A56】混炼示方批量删除性能优化-----------
|
||||||
|
|
||||||
|
private void saveChildren(
|
||||||
|
String mainId,
|
||||||
|
List<MesXslMixingSpecMaterial> materialList,
|
||||||
|
List<MesXslMixingSpecStep> stepList,
|
||||||
|
List<MesXslMixingSpecDownStep> downStepList,
|
||||||
|
List<MesXslMixingSpecTcu> tcuList) {
|
||||||
|
saveChildren(mainId, materialList, stepList, downStepList, tcuList, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveChildren(
|
||||||
|
String mainId,
|
||||||
|
List<MesXslMixingSpecMaterial> materialList,
|
||||||
|
List<MesXslMixingSpecStep> stepList,
|
||||||
|
List<MesXslMixingSpecDownStep> downStepList,
|
||||||
|
List<MesXslMixingSpecTcu> tcuList,
|
||||||
|
SavePerfTrace trace) {
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方子表批量插入避免保存超时-----------
|
||||||
|
Date now = new Date();
|
||||||
|
saveMaterialChildren(mainId, materialList, now, trace);
|
||||||
|
saveStepChildren(mainId, stepList, now, trace);
|
||||||
|
saveDownStepChildren(mainId, downStepList, now, trace);
|
||||||
|
saveTcuChildren(mainId, tcuList, now, trace);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方子表批量插入避免保存超时-----------
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方子表批量插入避免保存超时-----------
|
||||||
|
private void saveMaterialChildren(String mainId, List<MesXslMixingSpecMaterial> materialList, Date now) {
|
||||||
|
saveMaterialChildren(mainId, materialList, now, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveMaterialChildren(String mainId, List<MesXslMixingSpecMaterial> materialList, Date now, SavePerfTrace trace) {
|
||||||
|
if (CollectionUtils.isEmpty(materialList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计-----------
|
||||||
|
fillMaterialAccumWeight(materialList);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计-----------
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("fillMaterialAccumWeight", "rows", countRows(materialList));
|
||||||
|
}
|
||||||
|
List<MesXslMixingSpecMaterial> rows = new ArrayList<>();
|
||||||
|
int sort = 0;
|
||||||
|
for (MesXslMixingSpecMaterial row : materialList) {
|
||||||
|
if (row == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row.setId(null);
|
||||||
|
row.setMixingSpecId(mainId);
|
||||||
|
row.setSortNo(sort++);
|
||||||
|
if (row.getCreateTime() == null) {
|
||||||
|
row.setCreateTime(now);
|
||||||
|
}
|
||||||
|
rows.add(row);
|
||||||
|
}
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("buildMaterialRows", "rows", rows.size());
|
||||||
|
}
|
||||||
|
if (!rows.isEmpty()) {
|
||||||
|
Db.saveBatch(rows);
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("batchInsertMaterial", "rows", rows.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveStepChildren(String mainId, List<MesXslMixingSpecStep> stepList, Date now) {
|
||||||
|
saveStepChildren(mainId, stepList, now, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveStepChildren(String mainId, List<MesXslMixingSpecStep> stepList, Date now, SavePerfTrace trace) {
|
||||||
|
if (CollectionUtils.isEmpty(stepList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<MesXslMixingSpecStep> rows = new ArrayList<>();
|
||||||
|
int sort = 0;
|
||||||
|
for (MesXslMixingSpecStep row : stepList) {
|
||||||
|
if (row == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row.setId(null);
|
||||||
|
row.setMixingSpecId(mainId);
|
||||||
|
row.setSortNo(sort++);
|
||||||
|
if (row.getCreateTime() == null) {
|
||||||
|
row.setCreateTime(now);
|
||||||
|
}
|
||||||
|
rows.add(row);
|
||||||
|
}
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("buildStepRows", "rows", rows.size());
|
||||||
|
}
|
||||||
|
if (!rows.isEmpty()) {
|
||||||
|
Db.saveBatch(rows);
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("batchInsertStep", "rows", rows.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveDownStepChildren(String mainId, List<MesXslMixingSpecDownStep> downStepList, Date now) {
|
||||||
|
saveDownStepChildren(mainId, downStepList, now, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveDownStepChildren(String mainId, List<MesXslMixingSpecDownStep> downStepList, Date now, SavePerfTrace trace) {
|
||||||
|
if (CollectionUtils.isEmpty(downStepList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<MesXslMixingSpecDownStep> rows = new ArrayList<>();
|
||||||
|
int sort = 0;
|
||||||
|
for (MesXslMixingSpecDownStep row : downStepList) {
|
||||||
|
if (row == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row.setId(null);
|
||||||
|
row.setMixingSpecId(mainId);
|
||||||
|
row.setSortNo(sort++);
|
||||||
|
if (row.getCreateTime() == null) {
|
||||||
|
row.setCreateTime(now);
|
||||||
|
}
|
||||||
|
rows.add(row);
|
||||||
|
}
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("buildDownStepRows", "rows", rows.size());
|
||||||
|
}
|
||||||
|
if (!rows.isEmpty()) {
|
||||||
|
Db.saveBatch(rows);
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("batchInsertDownStep", "rows", rows.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveTcuChildren(String mainId, List<MesXslMixingSpecTcu> tcuList, Date now) {
|
||||||
|
saveTcuChildren(mainId, tcuList, now, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveTcuChildren(String mainId, List<MesXslMixingSpecTcu> tcuList, Date now, SavePerfTrace trace) {
|
||||||
|
List<MesXslMixingSpecTcu> tcuRows = fillDefaultTcuRows(tcuList);
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("fillDefaultTcuRows", "rows", tcuRows.size());
|
||||||
|
}
|
||||||
|
List<MesXslMixingSpecTcu> rows = new ArrayList<>();
|
||||||
|
int sort = 0;
|
||||||
|
for (MesXslMixingSpecTcu row : tcuRows) {
|
||||||
|
row.setId(null);
|
||||||
|
row.setMixingSpecId(mainId);
|
||||||
|
row.setSortNo(sort++);
|
||||||
|
if (row.getCreateTime() == null) {
|
||||||
|
row.setCreateTime(now);
|
||||||
|
}
|
||||||
|
if (TCU_DOWN.equals(row.getSectionType())) {
|
||||||
|
row.setDrugWeighPos(null);
|
||||||
|
}
|
||||||
|
rows.add(row);
|
||||||
|
}
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("buildTcuRows", "rows", rows.size());
|
||||||
|
}
|
||||||
|
if (!rows.isEmpty()) {
|
||||||
|
Db.saveBatch(rows);
|
||||||
|
if (trace != null) {
|
||||||
|
trace.step("batchInsertTcu", "rows", rows.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方子表批量插入避免保存超时-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
private static int countRows(List<?> rows) {
|
||||||
|
return rows == null ? 0 : rows.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 混炼示方保存性能追踪(临时诊断日志,定位慢步骤) */
|
||||||
|
private static final class SavePerfTrace {
|
||||||
|
private final String action;
|
||||||
|
private final String mainId;
|
||||||
|
private final String specName;
|
||||||
|
private final long startMs = System.currentTimeMillis();
|
||||||
|
private long lastMs = startMs;
|
||||||
|
private final StringBuilder summary = new StringBuilder();
|
||||||
|
|
||||||
|
private SavePerfTrace(String action, MesXslMixingSpec main) {
|
||||||
|
this.action = action;
|
||||||
|
this.mainId = main != null ? main.getId() : null;
|
||||||
|
this.specName = main != null ? main.getSpecName() : null;
|
||||||
|
summary.append("action=").append(action);
|
||||||
|
if (StringUtils.isNotBlank(mainId)) {
|
||||||
|
summary.append(", mainId=").append(mainId);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(specName)) {
|
||||||
|
summary.append(", specName=").append(specName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logPayloadSize(
|
||||||
|
List<MesXslMixingSpecMaterial> materialList,
|
||||||
|
List<MesXslMixingSpecStep> stepList,
|
||||||
|
List<MesXslMixingSpecDownStep> downStepList,
|
||||||
|
List<MesXslMixingSpecTcu> tcuList) {
|
||||||
|
log.info(
|
||||||
|
"[混炼示方保存性能] 开始{} specName={}, mainId={}, payload=[material={}, step={}, downStep={}, tcu={}]",
|
||||||
|
action,
|
||||||
|
specName,
|
||||||
|
mainId,
|
||||||
|
countRows(materialList),
|
||||||
|
countRows(stepList),
|
||||||
|
countRows(downStepList),
|
||||||
|
countRows(tcuList));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void step(String stepName, Object... kvPairs) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long stepMs = now - lastMs;
|
||||||
|
long totalMs = now - startMs;
|
||||||
|
summary.append(" | ").append(stepName).append('=').append(stepMs).append("ms");
|
||||||
|
if (kvPairs != null && kvPairs.length > 0) {
|
||||||
|
summary.append('(');
|
||||||
|
for (int i = 0; i < kvPairs.length; i += 2) {
|
||||||
|
if (i > 0) {
|
||||||
|
summary.append(", ");
|
||||||
|
}
|
||||||
|
summary.append(kvPairs[i]).append('=').append(kvPairs[i + 1]);
|
||||||
|
}
|
||||||
|
summary.append(')');
|
||||||
|
}
|
||||||
|
log.info("[混炼示方保存性能] {} 步骤={} 本步耗时={}ms 累计={}ms", action, stepName, stepMs, totalMs);
|
||||||
|
lastMs = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finish() {
|
||||||
|
log.info("[混炼示方保存性能] 完成{} 总耗时={}ms | {}", action, System.currentTimeMillis() - startMs, summary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A47】混炼示方保存分步骤性能日志-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计-----------
|
||||||
|
/** 按种类连续分组,累计写入每组最后一行 */
|
||||||
|
private void fillMaterialAccumWeight(List<MesXslMixingSpecMaterial> materials) {
|
||||||
|
if (CollectionUtils.isEmpty(materials)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int index = 0;
|
||||||
|
while (index < materials.size()) {
|
||||||
|
MesXslMixingSpecMaterial current = materials.get(index);
|
||||||
|
if (!isMaterialDataRow(current)) {
|
||||||
|
current.setAccumWeight(null);
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String kind = normalizeMaterialKind(current);
|
||||||
|
int groupEnd = index;
|
||||||
|
BigDecimal sum = BigDecimal.ZERO;
|
||||||
|
while (groupEnd < materials.size()) {
|
||||||
|
MesXslMixingSpecMaterial row = materials.get(groupEnd);
|
||||||
|
if (!isMaterialDataRow(row) || !kind.equals(normalizeMaterialKind(row))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (row.getUnitWeight() != null) {
|
||||||
|
sum = sum.add(row.getUnitWeight());
|
||||||
|
}
|
||||||
|
groupEnd++;
|
||||||
|
}
|
||||||
|
for (int rowIndex = index; rowIndex < groupEnd; rowIndex++) {
|
||||||
|
if (rowIndex == groupEnd - 1) {
|
||||||
|
materials.get(rowIndex).setAccumWeight(sum.compareTo(BigDecimal.ZERO) != 0 ? sum : null);
|
||||||
|
} else {
|
||||||
|
materials.get(rowIndex).setAccumWeight(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index = groupEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMaterialDataRow(MesXslMixingSpecMaterial row) {
|
||||||
|
if (row == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A55】混炼示方明细有效行判断含密炼物料ID-----------
|
||||||
|
return StringUtils.isNotBlank(row.getMixerMaterialName())
|
||||||
|
|| StringUtils.isNotBlank(row.getMixerMaterialId())
|
||||||
|
|| row.getUnitWeight() != null
|
||||||
|
|| StringUtils.isNotBlank(row.getMaterialKind());
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A55】混炼示方明细有效行判断含密炼物料ID-----------
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeMaterialKind(MesXslMixingSpecMaterial row) {
|
||||||
|
return StringUtils.isNotBlank(row.getMaterialKind()) ? row.getMaterialKind().trim() : "";
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A41】橡胶及配合剂明细累计按种类分组合计-----------
|
||||||
|
|
||||||
|
private List<MesXslMixingSpecMaterial> queryMaterialByMainId(String mainId) {
|
||||||
|
return materialMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<MesXslMixingSpecMaterial>()
|
||||||
|
.eq(MesXslMixingSpecMaterial::getMixingSpecId, mainId)
|
||||||
|
.orderByAsc(MesXslMixingSpecMaterial::getSortNo)
|
||||||
|
.orderByAsc(MesXslMixingSpecMaterial::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MesXslMixingSpecStep> queryStepByMainId(String mainId) {
|
||||||
|
return stepMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<MesXslMixingSpecStep>()
|
||||||
|
.eq(MesXslMixingSpecStep::getMixingSpecId, mainId)
|
||||||
|
.orderByAsc(MesXslMixingSpecStep::getSortNo)
|
||||||
|
.orderByAsc(MesXslMixingSpecStep::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MesXslMixingSpecDownStep> queryDownStepByMainId(String mainId) {
|
||||||
|
return downStepMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<MesXslMixingSpecDownStep>()
|
||||||
|
.eq(MesXslMixingSpecDownStep::getMixingSpecId, mainId)
|
||||||
|
.orderByAsc(MesXslMixingSpecDownStep::getSortNo)
|
||||||
|
.orderByAsc(MesXslMixingSpecDownStep::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MesXslMixingSpecTcu> queryTcuByMainId(String mainId) {
|
||||||
|
return tcuMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<MesXslMixingSpecTcu>()
|
||||||
|
.eq(MesXslMixingSpecTcu::getMixingSpecId, mainId)
|
||||||
|
.orderByAsc(MesXslMixingSpecTcu::getSortNo)
|
||||||
|
.orderByAsc(MesXslMixingSpecTcu::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MesXslMixingSpecTcu> fillDefaultTcuRows(List<MesXslMixingSpecTcu> source) {
|
||||||
|
List<MesXslMixingSpecTcu> rows = new ArrayList<>();
|
||||||
|
if (!CollectionUtils.isEmpty(source)) {
|
||||||
|
rows.addAll(source);
|
||||||
|
}
|
||||||
|
boolean hasUp = rows.stream().anyMatch(r -> TCU_UP.equals(r.getSectionType()));
|
||||||
|
boolean hasDown = rows.stream().anyMatch(r -> TCU_DOWN.equals(r.getSectionType()));
|
||||||
|
if (!hasUp) {
|
||||||
|
MesXslMixingSpecTcu up = new MesXslMixingSpecTcu();
|
||||||
|
up.setSectionType(TCU_UP);
|
||||||
|
rows.add(0, up);
|
||||||
|
}
|
||||||
|
if (!hasDown) {
|
||||||
|
MesXslMixingSpecTcu down = new MesXslMixingSpecTcu();
|
||||||
|
down.setSectionType(TCU_DOWN);
|
||||||
|
rows.add(down);
|
||||||
|
}
|
||||||
|
rows.sort((a, b) -> {
|
||||||
|
int ai = TCU_UP.equals(a.getSectionType()) ? 0 : TCU_DOWN.equals(a.getSectionType()) ? 1 : 2;
|
||||||
|
int bi = TCU_UP.equals(b.getSectionType()) ? 0 : TCU_DOWN.equals(b.getSectionType()) ? 1 : 2;
|
||||||
|
return Integer.compare(ai, bi);
|
||||||
|
});
|
||||||
|
if (rows.size() > 2) {
|
||||||
|
return new ArrayList<>(rows.subList(0, 2));
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料-----------
|
||||||
|
/**
|
||||||
|
* 删除混炼示方后,若该示方编号已无其它混炼示方且未被其它示方明细引用,则同步删除生成时写入的 B/F 段胶密炼物料。
|
||||||
|
*/
|
||||||
|
private void syncDeleteGeneratedRubberMixerMaterial(String specName) {
|
||||||
|
if (StringUtils.isBlank(specName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String specCode = specName.trim();
|
||||||
|
Boolean isFinalStage = resolveGeneratedRubberSegment(specCode);
|
||||||
|
if (isFinalStage == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long remainingSpecCount =
|
||||||
|
this.count(new LambdaQueryWrapper<MesXslMixingSpec>().eq(MesXslMixingSpec::getSpecName, specCode));
|
||||||
|
if (remainingSpecCount > 0) {
|
||||||
|
log.debug("[混炼示方删除] 示方编号 {} 仍有 {} 条混炼示方,跳过密炼物料同步删除", specCode, remainingSpecCount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long referencedCount = countMaterialReference(specCode, null);
|
||||||
|
if (referencedCount > 0) {
|
||||||
|
log.info(
|
||||||
|
"[混炼示方删除] 示方编号 {} 仍被 {} 条混炼示方明细引用,跳过密炼物料同步删除",
|
||||||
|
specCode,
|
||||||
|
referencedCount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MesMixerMaterial material = findMixerMaterialByCodeOrName(specCode);
|
||||||
|
if (material == null) {
|
||||||
|
log.debug("[混炼示方删除] 未找到示方编号 {} 对应密炼物料,跳过同步删除", specCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
referencedCount = countMaterialReference(specCode, material.getId());
|
||||||
|
if (referencedCount > 0) {
|
||||||
|
log.info(
|
||||||
|
"[混炼示方删除] 密炼物料 id={}, code={} 仍被 {} 条混炼示方明细引用,跳过同步删除",
|
||||||
|
material.getId(),
|
||||||
|
specCode,
|
||||||
|
referencedCount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, String> categoryIdCache = new HashMap<>();
|
||||||
|
if (!isGeneratedRubberMixerMaterial(material, isFinalStage, categoryIdCache)) {
|
||||||
|
log.info(
|
||||||
|
"[混炼示方删除] 密炼物料 id={}, code={} 分类非生成示方自动同步类型,跳过删除",
|
||||||
|
material.getId(),
|
||||||
|
specCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mesMixerMaterialService.removeById(material.getId());
|
||||||
|
log.info("[混炼示方删除] 同步删除密炼物料 id={}, code={}", material.getId(), specCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 判断是否为生成混炼示方时自动同步的 B/F 段胶示方编号;true=F段,false=B段,null=非自动生成胶料编号 */
|
||||||
|
private Boolean resolveGeneratedRubberSegment(String specCode) {
|
||||||
|
if (StringUtils.isBlank(specCode)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String normalized = specCode.trim();
|
||||||
|
if (normalized.toUpperCase().startsWith("F")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (GENERATED_B_RUBBER_SPEC_PATTERN.matcher(normalized).find()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MesMixerMaterial findMixerMaterialByCodeOrName(String specCode) {
|
||||||
|
MesMixerMaterial byCode = mesMixerMaterialService.getOne(
|
||||||
|
new LambdaQueryWrapper<MesMixerMaterial>()
|
||||||
|
.eq(MesMixerMaterial::getMaterialCode, specCode)
|
||||||
|
.and(w -> w.eq(MesMixerMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMixerMaterial::getDelFlag))
|
||||||
|
.last("limit 1"));
|
||||||
|
if (byCode != null) {
|
||||||
|
return byCode;
|
||||||
|
}
|
||||||
|
return mesMixerMaterialService.getOne(
|
||||||
|
new LambdaQueryWrapper<MesMixerMaterial>()
|
||||||
|
.eq(MesMixerMaterial::getMaterialName, specCode)
|
||||||
|
.and(w -> w.eq(MesMixerMaterial::getDelFlag, CommonConstant.DEL_FLAG_0).or().isNull(MesMixerMaterial::getDelFlag))
|
||||||
|
.last("limit 1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isGeneratedRubberMixerMaterial(
|
||||||
|
MesMixerMaterial material, boolean isFinalStage, Map<String, String> categoryIdCache) {
|
||||||
|
if (material == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String majorCode = isFinalStage ? CATEGORY_FINAL_MAJOR : CATEGORY_MASTER_MAJOR;
|
||||||
|
String minorCode = isFinalStage ? CATEGORY_FINAL_MINOR_Q : CATEGORY_MASTER_MINOR_A;
|
||||||
|
String expectedMajorId = resolveCategoryIdByCode(majorCode, categoryIdCache);
|
||||||
|
String expectedMinorId = resolveCategoryIdByCode(minorCode, categoryIdCache);
|
||||||
|
if (StringUtils.isBlank(expectedMajorId) || StringUtils.isBlank(expectedMinorId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return expectedMajorId.equals(material.getMajorCategoryId()) && expectedMinorId.equals(material.getMinorCategoryId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 统计混炼示方明细对某示方编号/密炼物料 ID 的引用次数 */
|
||||||
|
private long countMaterialReference(String specCode, String mixerMaterialId) {
|
||||||
|
LambdaQueryWrapper<MesXslMixingSpecMaterial> qw = new LambdaQueryWrapper<>();
|
||||||
|
qw.and(wrapper -> {
|
||||||
|
wrapper.eq(MesXslMixingSpecMaterial::getMixerMaterialName, specCode);
|
||||||
|
if (StringUtils.isNotBlank(mixerMaterialId)) {
|
||||||
|
wrapper.or().eq(MesXslMixingSpecMaterial::getMixerMaterialId, mixerMaterialId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return materialMapper.selectCount(qw);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveCategoryIdByCode(String categoryCode, Map<String, String> cache) {
|
||||||
|
if (StringUtils.isBlank(categoryCode)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (cache != null && cache.containsKey(categoryCode)) {
|
||||||
|
return cache.get(categoryCode);
|
||||||
|
}
|
||||||
|
SysCategory category = sysCategoryService.getOne(
|
||||||
|
new LambdaQueryWrapper<SysCategory>().eq(SysCategory::getCode, categoryCode.trim()).last("limit 1"));
|
||||||
|
String categoryId = category != null ? category.getId() : null;
|
||||||
|
if (cache != null) {
|
||||||
|
cache.put(categoryCode, categoryId);
|
||||||
|
}
|
||||||
|
return categoryId;
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A49】删除混炼示方时同步删除B/F段胶密炼物料-----------
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.jeecg.modules.xslmes.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/** 生成混炼示方:机台 */
|
||||||
|
@Data
|
||||||
|
@Schema(description = "生成混炼示方机台")
|
||||||
|
public class MesXslFormulaMixingGenerateMachineVO {
|
||||||
|
|
||||||
|
@Schema(description = "设备台账ID")
|
||||||
|
private String machineId;
|
||||||
|
|
||||||
|
@Schema(description = "机台名称")
|
||||||
|
private String machineName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.jeecg.modules.xslmes.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/** 生成混炼示方:预览行 */
|
||||||
|
@Data
|
||||||
|
@Schema(description = "生成混炼示方预览行")
|
||||||
|
public class MesXslFormulaMixingGeneratePreviewItemVO {
|
||||||
|
|
||||||
|
@Schema(description = "行键(段序号)")
|
||||||
|
private Integer rowKey;
|
||||||
|
|
||||||
|
@Schema(description = "示方编号(规格)")
|
||||||
|
private String specCode;
|
||||||
|
|
||||||
|
@Schema(description = "混合段序号 1-7")
|
||||||
|
private Integer stageIndex;
|
||||||
|
|
||||||
|
@Schema(description = "段类型:A 或 Q")
|
||||||
|
private String stepType;
|
||||||
|
|
||||||
|
@Schema(description = "A段序号(仅A段有值)")
|
||||||
|
private Integer aSegmentIndex;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.jeecg.modules.xslmes.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/** 生成混炼示方:预览结果 */
|
||||||
|
@Data
|
||||||
|
@Schema(description = "生成混炼示方预览")
|
||||||
|
public class MesXslFormulaMixingGeneratePreviewVO {
|
||||||
|
|
||||||
|
@Schema(description = "配合示方ID")
|
||||||
|
private String formulaSpecId;
|
||||||
|
|
||||||
|
@Schema(description = "胶料名称")
|
||||||
|
private String rubberName;
|
||||||
|
|
||||||
|
@Schema(description = "混合段数")
|
||||||
|
private Integer mixingStages;
|
||||||
|
|
||||||
|
@Schema(description = "预览行")
|
||||||
|
private List<MesXslFormulaMixingGeneratePreviewItemVO> items;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.jeecg.modules.xslmes.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/** 生成混炼示方:确认请求 */
|
||||||
|
@Data
|
||||||
|
@Schema(description = "生成混炼示方确认请求")
|
||||||
|
public class MesXslFormulaMixingGenerateRequestVO {
|
||||||
|
|
||||||
|
@Schema(description = "配合示方ID")
|
||||||
|
private String formulaSpecId;
|
||||||
|
|
||||||
|
@Schema(description = "确认行")
|
||||||
|
private List<MesXslFormulaMixingGenerateRowVO> rows;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.jeecg.modules.xslmes.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/** 生成混炼示方:确认行(含机台) */
|
||||||
|
@Data
|
||||||
|
@Schema(description = "生成混炼示方确认行")
|
||||||
|
public class MesXslFormulaMixingGenerateRowVO {
|
||||||
|
|
||||||
|
@Schema(description = "示方编号(规格)")
|
||||||
|
private String specCode;
|
||||||
|
|
||||||
|
@Schema(description = "混合段序号 1-7")
|
||||||
|
private Integer stageIndex;
|
||||||
|
|
||||||
|
@Schema(description = "A段序号(B1/B2…,仅A段有值)")
|
||||||
|
private Integer aSegmentIndex;
|
||||||
|
|
||||||
|
@Schema(description = "段类型:A 或 Q")
|
||||||
|
private String stepType;
|
||||||
|
|
||||||
|
@Schema(description = "机台列表")
|
||||||
|
private List<MesXslFormulaMixingGenerateMachineVO> machines;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.jeecg.modules.xslmes.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密炼物料种类配置查找表(按对应分类/字典项关联)
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "密炼物料种类配置查找表")
|
||||||
|
public class MesXslMixerMaterialKindLookupVO implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "对应分类/字典项ID -> 种类名称")
|
||||||
|
private Map<String, String> byRefId = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
@Schema(description = "对应分类/字典项编码 -> 种类名称")
|
||||||
|
private Map<String, String> byRefCode = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
@Schema(description = "胶料种类名称(母炼胶行兜底)")
|
||||||
|
private String rubberKindName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.jeecg.modules.xslmes.vo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecStep;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecTcu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 混炼示方主子保存VO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class MesXslMixingSpecPage extends MesXslMixingSpec {
|
||||||
|
private List<MesXslMixingSpecMaterial> materialList;
|
||||||
|
private List<MesXslMixingSpecStep> stepList;
|
||||||
|
private List<MesXslMixingSpecDownStep> downStepList;
|
||||||
|
private List<MesXslMixingSpecTcu> tcuList;
|
||||||
|
}
|
||||||
@@ -418,6 +418,14 @@ jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/MesXslEquipInspectRecor
|
|||||||
jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/MesXslEquipInspectRecordList.vue
|
jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/MesXslEquipInspectRecordList.vue
|
||||||
jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/components/MesXslEquipInspectRecordModal.vue
|
jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/components/MesXslEquipInspectRecordModal.vue
|
||||||
jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/components/MesXslEquipInspectRecordHandleModal.vue
|
jeecgboot-vue3/src/views/xslmes/mesXslEquipInspectRecord/components/MesXslEquipInspectRecordHandleModal.vue
|
||||||
|
-- author:cursor---date:20260522--for: 【XSLMES-20260522-A31】分类字典原辅材料子类增加胶料标记字段 ---
|
||||||
|
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_99__sys_category_is_rubber.sql
|
||||||
|
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysCategory.java
|
||||||
|
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java
|
||||||
|
jeecgboot-vue3/src/views/system/category/category.constants.ts
|
||||||
|
jeecgboot-vue3/src/views/system/category/category.data.ts
|
||||||
|
jeecgboot-vue3/src/views/system/category/components/CategoryModal.vue
|
||||||
|
jeecgboot-vue3/src/views/mes/material/modules/MesMixerMaterialSysCategoryModal.vue
|
||||||
|
|
||||||
-- author:jiangxh---date:20260522--for: 【MES】胶料快检实验类型:质量管理目录、001自动编号、CRUD与菜单权限 ---
|
-- author:jiangxh---date:20260522--for: 【MES】胶料快检实验类型:质量管理目录、001自动编号、CRUD与菜单权限 ---
|
||||||
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_97__mes_xsl_rubber_quick_test_type.sql
|
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_97__mes_xsl_rubber_quick_test_type.sql
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ public class SysCategory implements Serializable,Comparable<SysCategory>{
|
|||||||
/**是否有子节点*/
|
/**是否有子节点*/
|
||||||
@Excel(name = "是否有子节点(1:有)", width = 15)
|
@Excel(name = "是否有子节点(1:有)", width = 15)
|
||||||
private java.lang.String hasChild;
|
private java.lang.String hasChild;
|
||||||
|
/**是否胶料(仅原辅材料子类有效) 1是/0否*/
|
||||||
|
@Excel(name = "是否胶料", width = 15)
|
||||||
|
private java.lang.String isRubber;
|
||||||
|
|
||||||
/**租户ID*/
|
/**租户ID*/
|
||||||
private java.lang.Integer tenantId;
|
private java.lang.Integer tenantId;
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ import java.util.stream.Collectors;
|
|||||||
@Service
|
@Service
|
||||||
public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCategory> implements ISysCategoryService {
|
public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCategory> implements ISysCategoryService {
|
||||||
|
|
||||||
|
/** MES 物料大类编码前缀(其直接子类为物料小类,可标记胶料) */
|
||||||
|
private static final String MATERIAL_MAJOR_CODE_PREFIX = "XSLMES_MATERIAL_";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addSysCategory(SysCategory sysCategory) {
|
public void addSysCategory(SysCategory sysCategory) {
|
||||||
String categoryPid = ISysCategoryService.ROOT_PID_VALUE;
|
String categoryPid = ISysCategoryService.ROOT_PID_VALUE;
|
||||||
@@ -64,6 +67,9 @@ public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCa
|
|||||||
sysCategory.setCode(customCode);
|
sysCategory.setCode(customCode);
|
||||||
}
|
}
|
||||||
sysCategory.setPid(categoryPid);
|
sysCategory.setPid(categoryPid);
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A31】原辅材料子类胶料标记归一化-----------
|
||||||
|
normalizeIsRubber(sysCategory);
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A31】原辅材料子类胶料标记归一化-----------
|
||||||
baseMapper.insert(sysCategory);
|
baseMapper.insert(sysCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,9 +97,41 @@ public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCa
|
|||||||
}
|
}
|
||||||
sysCategory.setCode(newCode);
|
sysCategory.setCode(newCode);
|
||||||
}
|
}
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A31】原辅材料子类胶料标记归一化-----------
|
||||||
|
normalizeIsRubber(sysCategory);
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A31】原辅材料子类胶料标记归一化-----------
|
||||||
baseMapper.updateById(sysCategory);
|
baseMapper.updateById(sysCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】MES物料小类均可维护是否胶料-----------
|
||||||
|
/**
|
||||||
|
* 胶料标记仅对 MES 物料小类(父节点为物料大类)生效,其余节点强制为 0。
|
||||||
|
*/
|
||||||
|
private void normalizeIsRubber(SysCategory sysCategory) {
|
||||||
|
if (sysCategory == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!"1".equals(sysCategory.getIsRubber())) {
|
||||||
|
sysCategory.setIsRubber("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isMaterialMinorCategory(sysCategory)) {
|
||||||
|
sysCategory.setIsRubber("0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMaterialMinorCategory(SysCategory category) {
|
||||||
|
if (category == null || oConvertUtils.isEmpty(category.getPid())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SysCategory parent = baseMapper.selectById(category.getPid());
|
||||||
|
if (parent == null || oConvertUtils.isEmpty(parent.getCode())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return parent.getCode().startsWith(MATERIAL_MAJOR_CODE_PREFIX);
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】MES物料小类均可维护是否胶料-----------
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TreeSelectModel> queryListByCode(String pcode) throws JeecgBootException{
|
public List<TreeSelectModel> queryListByCode(String pcode) throws JeecgBootException{
|
||||||
String pid = ROOT_PID_VALUE;
|
String pid = ROOT_PID_VALUE;
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- 段数存「当前段/总段数」文本,如 2/3(不新增字段)
|
||||||
|
ALTER TABLE `mes_xsl_mixing_spec`
|
||||||
|
MODIFY COLUMN `stage_count` varchar(20) DEFAULT NULL COMMENT '段数(当前/总)';
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- 回退误加的 stage_count_total,并确保 stage_count 为 varchar
|
||||||
|
ALTER TABLE `mes_xsl_mixing_spec` DROP COLUMN IF EXISTS `stage_count_total`;
|
||||||
|
ALTER TABLE `mes_xsl_mixing_spec`
|
||||||
|
MODIFY COLUMN `stage_count` varchar(20) DEFAULT NULL COMMENT '段数(当前/总)';
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
-- 密炼物料种类配置:建表 + 菜单(挂 MES技术管理)+ admin 授权
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `mes_xsl_mixer_material_kind_cfg` (
|
||||||
|
`id` varchar(32) NOT NULL COMMENT '主键',
|
||||||
|
`kind_key` varchar(100) NOT NULL COMMENT '种类键值',
|
||||||
|
`kind_name` varchar(200) NOT NULL COMMENT '种类名称',
|
||||||
|
`source_type` varchar(20) NOT NULL COMMENT '数据源类型:dict数据字典/category分类字典',
|
||||||
|
`source_root_code` varchar(100) DEFAULT NULL COMMENT '根字典编码或分类pcode',
|
||||||
|
`source_root_name` varchar(200) DEFAULT NULL COMMENT '根名称冗余',
|
||||||
|
`category_ref_id` varchar(32) DEFAULT NULL COMMENT '对应分类/字典项ID',
|
||||||
|
`category_ref_code` varchar(100) DEFAULT NULL COMMENT '对应分类编码/字典项值',
|
||||||
|
`category_ref_name` varchar(200) DEFAULT NULL COMMENT '对应分类名称冗余',
|
||||||
|
`tenant_id` int DEFAULT NULL COMMENT '租户ID',
|
||||||
|
`priority` int DEFAULT '0' COMMENT '优先级(数字越小越优先)',
|
||||||
|
`sys_org_code` varchar(64) DEFAULT NULL COMMENT '所属部门',
|
||||||
|
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(50) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||||
|
`del_flag` int NOT NULL DEFAULT '0' COMMENT '逻辑删除(0正常 1已删除)',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_mxmmkc_tenant_priority` (`tenant_id`, `priority`),
|
||||||
|
KEY `idx_mxmmkc_source_root` (`source_type`, `source_root_code`),
|
||||||
|
KEY `idx_mxmmkc_category_ref` (`category_ref_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES密炼物料种类配置';
|
||||||
|
|
||||||
|
UPDATE `sys_permission`
|
||||||
|
SET `is_leaf` = 0, `update_time` = NOW()
|
||||||
|
WHERE `id` = '1900000000000000810' AND `is_leaf` = 1;
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (
|
||||||
|
`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`,
|
||||||
|
`menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`,
|
||||||
|
`hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`,
|
||||||
|
`del_flag`, `rule_flag`, `status`, `internal_or_external`
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'177925970995550', '1900000000000000810', '密炼物料种类配置', '/xslmes/mesXslMixerMaterialKindCfg',
|
||||||
|
'xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList', 1, 'MesXslMixerMaterialKindCfgList', NULL,
|
||||||
|
1, NULL, '0', 3.00, 0, 'ant-design:tags-outlined', 0, 1,
|
||||||
|
0, 0, 'MES密炼物料种类配置', 'admin', NOW(), 'admin', NOW(),
|
||||||
|
0, 0, '1', 0
|
||||||
|
FROM DUAL
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM `sys_permission`
|
||||||
|
WHERE `id` = '177925970995550'
|
||||||
|
OR (`del_flag` = 0 AND `menu_type` = 1 AND `name` = '密炼物料种类配置' AND `parent_id` = '1900000000000000810')
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995551', '177925970995550', '新增', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:add', '1', 1.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995551');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995552', '177925970995550', '编辑', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:edit', '1', 2.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995552');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995553', '177925970995550', '删除', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:delete', '1', 3.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995553');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995554', '177925970995550', '批量删除', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:deleteBatch', '1', 4.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995554');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995555', '177925970995550', '导出', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:exportXls', '1', 5.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995555');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995556', '177925970995550', '导入', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:importExcel', '1', 6.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995556');
|
||||||
|
|
||||||
|
INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
|
||||||
|
SELECT REPLACE(UUID(), '-', ''), r.id, p.id, NULL, NOW(), '127.0.0.1'
|
||||||
|
FROM `sys_role` r
|
||||||
|
CROSS JOIN `sys_permission` p
|
||||||
|
WHERE r.`role_code` = 'admin'
|
||||||
|
AND p.`id` IN (
|
||||||
|
'177925970995550',
|
||||||
|
'177925970995551',
|
||||||
|
'177925970995552',
|
||||||
|
'177925970995553',
|
||||||
|
'177925970995554',
|
||||||
|
'177925970995555',
|
||||||
|
'177925970995556'
|
||||||
|
)
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM `sys_role_permission` rp WHERE rp.`role_id` = r.`id` AND rp.`permission_id` = p.`id`
|
||||||
|
);
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
-- 密炼物料种类配置:菜单 ID 与配合示方(177925970995530)冲突,补插正确菜单
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
UPDATE `sys_permission`
|
||||||
|
SET `is_leaf` = 0, `update_time` = NOW()
|
||||||
|
WHERE `id` = '1900000000000000810';
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (
|
||||||
|
`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`,
|
||||||
|
`menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`,
|
||||||
|
`hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`,
|
||||||
|
`del_flag`, `rule_flag`, `status`, `internal_or_external`
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'177925970995550', '1900000000000000810', '密炼物料种类配置', '/xslmes/mesXslMixerMaterialKindCfg',
|
||||||
|
'xslmes/mesXslMixerMaterialKindCfg/MesXslMixerMaterialKindCfgList', 1, 'MesXslMixerMaterialKindCfgList', NULL,
|
||||||
|
1, NULL, '0', 3.00, 0, 'ant-design:tags-outlined', 0, 1,
|
||||||
|
0, 0, 'MES密炼物料种类配置', 'admin', NOW(), 'admin', NOW(),
|
||||||
|
0, 0, '1', 0
|
||||||
|
FROM DUAL
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM `sys_permission`
|
||||||
|
WHERE `id` = '177925970995550'
|
||||||
|
OR (`del_flag` = 0 AND `menu_type` = 1 AND `name` = '密炼物料种类配置' AND `parent_id` = '1900000000000000810')
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995551', '177925970995550', '新增', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:add', '1', 1.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995551');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995552', '177925970995550', '编辑', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:edit', '1', 2.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995552');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995553', '177925970995550', '删除', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:delete', '1', 3.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995553');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995554', '177925970995550', '批量删除', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:deleteBatch', '1', 4.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995554');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995555', '177925970995550', '导出', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:exportXls', '1', 5.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995555');
|
||||||
|
|
||||||
|
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
SELECT '177925970995556', '177925970995550', '导入', 2, 'xslmes:mes_xsl_mixer_material_kind_cfg:importExcel', '1', 6.00, 0, 1, 0, '1', 0, 'admin', NOW()
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '177925970995556');
|
||||||
|
|
||||||
|
INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
|
||||||
|
SELECT REPLACE(UUID(), '-', ''), r.id, p.id, NULL, NOW(), '127.0.0.1'
|
||||||
|
FROM `sys_role` r
|
||||||
|
CROSS JOIN `sys_permission` p
|
||||||
|
WHERE r.`role_code` = 'admin'
|
||||||
|
AND p.`id` IN (
|
||||||
|
'177925970995550',
|
||||||
|
'177925970995551',
|
||||||
|
'177925970995552',
|
||||||
|
'177925970995553',
|
||||||
|
'177925970995554',
|
||||||
|
'177925970995555',
|
||||||
|
'177925970995556'
|
||||||
|
)
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM `sys_role_permission` rp WHERE rp.`role_id` = r.`id` AND rp.`permission_id` = p.`id`
|
||||||
|
);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
-- 混炼示方明细:关联密炼物料主数据 ID
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
ALTER TABLE `mes_xsl_mixing_spec_material`
|
||||||
|
ADD COLUMN `mixer_material_id` varchar(32) DEFAULT NULL COMMENT '密炼物料ID(关联mes_mixer_material.id)' AFTER `material_kind`;
|
||||||
|
|
||||||
|
CREATE INDEX `idx_mxmix_mat_mixer_id` ON `mes_xsl_mixing_spec_material` (`mixer_material_id`);
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
-- 配合示方状态字典:编制/提交审批/检讨审批/承认审批/作废/尚未到生效期
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
UPDATE `sys_dict`
|
||||||
|
SET `description` = 'MES配合示方状态(编制/提交审批/检讨/承认/作废/生效期)', `update_by` = 'admin', `update_time` = NOW()
|
||||||
|
WHERE `id` = '1995000000000000013';
|
||||||
|
|
||||||
|
UPDATE `sys_dict_item`
|
||||||
|
SET `item_text` = '编制', `item_value` = 'compile', `sort_order` = 1, `update_by` = 'admin', `update_time` = NOW()
|
||||||
|
WHERE `id` = '1995000000000001031';
|
||||||
|
|
||||||
|
UPDATE `sys_dict_item`
|
||||||
|
SET `item_text` = '提交审批', `item_value` = 'submit', `sort_order` = 2, `update_by` = 'admin', `update_time` = NOW()
|
||||||
|
WHERE `id` = '1995000000000001032';
|
||||||
|
|
||||||
|
UPDATE `sys_dict_item`
|
||||||
|
SET `item_text` = '检讨审批通过', `item_value` = 'review_pass', `sort_order` = 3, `update_by` = 'admin', `update_time` = NOW()
|
||||||
|
WHERE `id` = '1995000000000001033';
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
|
||||||
|
VALUES ('1995000000000001037', '1995000000000000013', '检讨审批退回', 'review_return', 4, 1, 'admin', NOW());
|
||||||
|
|
||||||
|
UPDATE `sys_dict_item`
|
||||||
|
SET `item_text` = '承认审批通过-即正式发布', `item_value` = 'recognition_pass', `sort_order` = 5, `update_by` = 'admin', `update_time` = NOW()
|
||||||
|
WHERE `id` = '1995000000000001034';
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
|
||||||
|
VALUES ('1995000000000001038', '1995000000000000013', '承认审批退回', 'recognition_return', 6, 1, 'admin', NOW());
|
||||||
|
|
||||||
|
UPDATE `sys_dict_item`
|
||||||
|
SET `item_text` = '作废', `item_value` = 'obsolete', `sort_order` = 7, `update_by` = 'admin', `update_time` = NOW()
|
||||||
|
WHERE `id` = '1995000000000001035';
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
|
||||||
|
VALUES ('1995000000000001039', '1995000000000000013', '尚未到生效期', 'not_effective', 8, 1, 'admin', NOW());
|
||||||
|
|
||||||
|
UPDATE `sys_dict_item` SET `status` = 0, `update_by` = 'admin', `update_time` = NOW()
|
||||||
|
WHERE `dict_id` = '1995000000000000013' AND `id` = '1995000000000001036';
|
||||||
|
|
||||||
|
UPDATE `mes_xsl_formula_spec` SET `status` = 'submit' WHERE `status` = 'proofread';
|
||||||
|
UPDATE `mes_xsl_formula_spec` SET `status` = 'review_pass' WHERE `status` = 'audit';
|
||||||
|
UPDATE `mes_xsl_formula_spec` SET `status` = 'recognition_pass' WHERE `status` IN ('approve', 'released');
|
||||||
|
|
||||||
|
ALTER TABLE `mes_xsl_formula_spec`
|
||||||
|
MODIFY COLUMN `status` varchar(32) DEFAULT 'compile' COMMENT '状态(字典xslmes_formula_spec_status:compile编制 submit提交审批 review_pass检讨通过 review_return检讨退回 recognition_pass承认通过 recognition_return承认退回 obsolete作废 not_effective尚未生效)';
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
|
||||||
|
VALUES ('1995000000000000098', '混炼TCU区分', 'xslmes_mixing_tcu_section', '混炼示方TCU区分', 0, 'admin', NOW(), 0, 1002);
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
|
||||||
|
VALUES ('1995000000000009801', '1995000000000000098', '上密炼机', 'up_mixer', 1, 1, 'admin', NOW());
|
||||||
|
INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
|
||||||
|
VALUES ('1995000000000009802', '1995000000000000098', '下密炼机', 'down_mixer', 2, 1, 'admin', NOW());
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
|
||||||
|
VALUES ('1995000000000000099', '混炼药品称量位置', 'xslmes_mixing_drug_weigh_pos', '混炼示方药品称量位置', 0, 'admin', NOW(), 0, 1002);
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
|
||||||
|
VALUES ('1995000000000009901', '1995000000000000099', '药品称', 'drug_scale', 1, 1, 'admin', NOW());
|
||||||
|
INSERT IGNORE INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
|
||||||
|
VALUES ('1995000000000009902', '1995000000000000099', '胶料称', 'rubber_scale', 2, 1, 'admin', NOW());
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec` (
|
||||||
|
`id` varchar(32) NOT NULL COMMENT '主键',
|
||||||
|
`tenant_id` int DEFAULT NULL COMMENT '租户ID',
|
||||||
|
`spec_name` varchar(120) DEFAULT NULL COMMENT '规格',
|
||||||
|
`purpose` varchar(300) DEFAULT NULL COMMENT '用途',
|
||||||
|
`machine_id` varchar(32) DEFAULT NULL COMMENT '机台ID',
|
||||||
|
`machine_name` varchar(120) DEFAULT NULL COMMENT '机台',
|
||||||
|
`make_date` date DEFAULT NULL COMMENT '制作日期',
|
||||||
|
`issue_number` varchar(120) DEFAULT NULL COMMENT '发行编号',
|
||||||
|
`convert_factor` decimal(18,6) DEFAULT NULL COMMENT '换算系数',
|
||||||
|
`fill_volume` decimal(18,6) DEFAULT NULL COMMENT '填充体积',
|
||||||
|
`recycle_carbon_sec` int DEFAULT NULL COMMENT '回收炭黑(秒)',
|
||||||
|
`mother_rubber_sg` decimal(18,6) DEFAULT NULL COMMENT '母胶比重',
|
||||||
|
`final_rubber_sg` decimal(18,6) DEFAULT NULL COMMENT '终炼胶比重',
|
||||||
|
`apply_factory` varchar(120) DEFAULT NULL COMMENT '适用工厂',
|
||||||
|
`stage_count` int DEFAULT NULL COMMENT '段数',
|
||||||
|
`pure_mix_sec` int DEFAULT NULL COMMENT '纯混炼时间(秒)',
|
||||||
|
`recycle_carbon_kg` decimal(18,6) DEFAULT NULL COMMENT '回收炭黑(KG)',
|
||||||
|
`auto_small_print_setting` varchar(200) DEFAULT NULL COMMENT '自动小料打印设定',
|
||||||
|
`set_train_count` int DEFAULT NULL COMMENT '设定车数',
|
||||||
|
`side_wall_water_temp` decimal(18,6) DEFAULT NULL COMMENT '侧壁水温',
|
||||||
|
`overtime_discharge_sec` int DEFAULT NULL COMMENT '超时排胶时间',
|
||||||
|
`overtemp_discharge_sec` int DEFAULT NULL COMMENT '超温排胶时间',
|
||||||
|
`overtemp_discharge_temp` decimal(18,6) DEFAULT NULL COMMENT '超温排胶温度',
|
||||||
|
`door_water_temp` decimal(18,6) DEFAULT NULL COMMENT '卸料门水温',
|
||||||
|
`rotor_water_temp` decimal(18,6) DEFAULT NULL COMMENT '转子水温',
|
||||||
|
`max_feed_temp` decimal(18,6) DEFAULT NULL COMMENT '最高进料温度',
|
||||||
|
`draft_by` varchar(80) DEFAULT NULL COMMENT '起草人',
|
||||||
|
`draft_time` datetime DEFAULT NULL COMMENT '起草时间',
|
||||||
|
`proofread_by` varchar(80) DEFAULT NULL COMMENT '校对人',
|
||||||
|
`proofread_time` datetime DEFAULT NULL COMMENT '校对时间',
|
||||||
|
`audit_by` varchar(80) DEFAULT NULL COMMENT '审核人',
|
||||||
|
`audit_time` datetime DEFAULT NULL COMMENT '审核时间',
|
||||||
|
`approve_by` varchar(80) DEFAULT NULL COMMENT '批准人',
|
||||||
|
`approve_time` datetime DEFAULT NULL COMMENT '批准时间',
|
||||||
|
`change_date` date DEFAULT NULL COMMENT '变更日期',
|
||||||
|
`sys_org_code` varchar(64) DEFAULT NULL COMMENT '所属部门',
|
||||||
|
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(50) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||||
|
`del_flag` int NOT NULL DEFAULT 0 COMMENT '逻辑删除',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_mxmix_issue_number` (`issue_number`),
|
||||||
|
KEY `idx_mxmix_spec_name` (`spec_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec_material` (
|
||||||
|
`id` varchar(32) NOT NULL COMMENT '主键',
|
||||||
|
`mixing_spec_id` varchar(32) NOT NULL COMMENT '混炼示方主表ID',
|
||||||
|
`sort_no` int DEFAULT NULL COMMENT '行序号',
|
||||||
|
`material_major` varchar(120) DEFAULT NULL COMMENT '物料大类',
|
||||||
|
`material_minor` varchar(120) DEFAULT NULL COMMENT '物料小类',
|
||||||
|
`material_kind` varchar(120) DEFAULT NULL COMMENT '种类',
|
||||||
|
`mixer_material_name` varchar(200) DEFAULT NULL COMMENT '密炼物料名称',
|
||||||
|
`mixer_material_desc` varchar(300) DEFAULT NULL COMMENT '密炼物料描述',
|
||||||
|
`unit_weight` decimal(18,6) DEFAULT NULL COMMENT '单重',
|
||||||
|
`accum_weight` decimal(18,6) DEFAULT NULL COMMENT '累计',
|
||||||
|
`seq_no` int DEFAULT NULL COMMENT '顺序',
|
||||||
|
`tenant_id` int DEFAULT NULL COMMENT '租户ID',
|
||||||
|
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(50) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_mxmix_mat_main` (`mixing_spec_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方明细-橡胶及配合剂';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec_step` (
|
||||||
|
`id` varchar(32) NOT NULL COMMENT '主键',
|
||||||
|
`mixing_spec_id` varchar(32) NOT NULL COMMENT '混炼示方主表ID',
|
||||||
|
`sort_no` int DEFAULT NULL COMMENT '行序号',
|
||||||
|
`action_name` varchar(120) DEFAULT NULL COMMENT '动作',
|
||||||
|
`action_sec` int DEFAULT NULL COMMENT '时间(秒)',
|
||||||
|
`protect_sec` int DEFAULT NULL COMMENT '保护时间',
|
||||||
|
`temp_c` decimal(18,6) DEFAULT NULL COMMENT '温度(℃)',
|
||||||
|
`power_kw` decimal(18,6) DEFAULT NULL COMMENT '功率(Kw)',
|
||||||
|
`energy_kwh` decimal(18,6) DEFAULT NULL COMMENT '能量(Kwh)',
|
||||||
|
`combo_mode` varchar(120) DEFAULT NULL COMMENT '组合',
|
||||||
|
`speed_rpm` decimal(18,6) DEFAULT NULL COMMENT '转速(rpm)',
|
||||||
|
`pressure_mpa` decimal(18,6) DEFAULT NULL COMMENT '压力(Mpa)',
|
||||||
|
`bolt_percent` decimal(18,6) DEFAULT NULL COMMENT '栓(%)',
|
||||||
|
`tenant_id` int DEFAULT NULL COMMENT '租户ID',
|
||||||
|
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(50) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_mxmix_step_main` (`mixing_spec_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方明细-混合步骤';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec_down_step` (
|
||||||
|
`id` varchar(32) NOT NULL COMMENT '主键',
|
||||||
|
`mixing_spec_id` varchar(32) NOT NULL COMMENT '混炼示方主表ID',
|
||||||
|
`sort_no` int DEFAULT NULL COMMENT '行序号',
|
||||||
|
`action_name` varchar(120) DEFAULT NULL COMMENT '动作',
|
||||||
|
`action_sec` int DEFAULT NULL COMMENT '时间(秒)',
|
||||||
|
`protect_sec` int DEFAULT NULL COMMENT '保护时间',
|
||||||
|
`temp_c` decimal(18,6) DEFAULT NULL COMMENT '温度(℃)',
|
||||||
|
`power_kw` decimal(18,6) DEFAULT NULL COMMENT '功率(Kw)',
|
||||||
|
`energy_kwh` decimal(18,6) DEFAULT NULL COMMENT '能量(Kwh)',
|
||||||
|
`combo_mode` varchar(120) DEFAULT NULL COMMENT '组合',
|
||||||
|
`speed_rpm` decimal(18,6) DEFAULT NULL COMMENT '转速(rpm)',
|
||||||
|
`pressure_mpa` decimal(18,6) DEFAULT NULL COMMENT '压力(Mpa)',
|
||||||
|
`bolt_percent` decimal(18,6) DEFAULT NULL COMMENT '栓(%)',
|
||||||
|
`tenant_id` int DEFAULT NULL COMMENT '租户ID',
|
||||||
|
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(50) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_mxmix_down_step_main` (`mixing_spec_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方明细-下密炼机混炼条件';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `mes_xsl_mixing_spec_tcu` (
|
||||||
|
`id` varchar(32) NOT NULL COMMENT '主键',
|
||||||
|
`mixing_spec_id` varchar(32) NOT NULL COMMENT '混炼示方主表ID',
|
||||||
|
`sort_no` int DEFAULT NULL COMMENT '行序号',
|
||||||
|
`section_type` varchar(32) DEFAULT NULL COMMENT '区分(上密炼机/下密炼机)',
|
||||||
|
`front_rotor_temp` decimal(18,6) DEFAULT NULL COMMENT '前转子温度',
|
||||||
|
`rear_rotor_temp` decimal(18,6) DEFAULT NULL COMMENT '后转子温度',
|
||||||
|
`front_chamber_temp` decimal(18,6) DEFAULT NULL COMMENT '前混炼室温度',
|
||||||
|
`rear_chamber_temp` decimal(18,6) DEFAULT NULL COMMENT '后混炼室温度',
|
||||||
|
`top_plug_temp` decimal(18,6) DEFAULT NULL COMMENT '上下顶栓温度',
|
||||||
|
`drug_weigh_pos` varchar(32) DEFAULT NULL COMMENT '药品称量位置',
|
||||||
|
`tenant_id` int DEFAULT NULL COMMENT '租户ID',
|
||||||
|
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(50) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_mxmix_tcu_main` (`mixing_spec_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES混炼示方明细-TCU温度条件';
|
||||||
|
|
||||||
|
UPDATE `sys_permission`
|
||||||
|
SET `is_leaf` = 0, `update_time` = NOW()
|
||||||
|
WHERE `id` = '1900000000000000810' AND `is_leaf` = 1;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `sys_permission` (
|
||||||
|
`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`,
|
||||||
|
`menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`,
|
||||||
|
`hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`,
|
||||||
|
`del_flag`, `rule_flag`, `status`, `internal_or_external`
|
||||||
|
) VALUES (
|
||||||
|
'177925970995540', '1900000000000000810', '混炼示方', '/xslmes/mesXslMixingSpec',
|
||||||
|
'xslmes/mesXslMixingSpec/MesXslMixingSpecList', 1, 'MesXslMixingSpecList', NULL,
|
||||||
|
1, NULL, '0', 2.00, 0, 'ant-design:table-outlined', 0, 1,
|
||||||
|
0, 0, 'MES混炼示方', 'admin', NOW(), 'admin', NOW(),
|
||||||
|
0, 0, '1', 0
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES ('177925970995541', '177925970995540', '新增', 2, 'xslmes:mes_xsl_mixing_spec:add', '1', 1.00, 0, 1, 0, '1', 0, 'admin', NOW());
|
||||||
|
INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES ('177925970995542', '177925970995540', '编辑', 2, 'xslmes:mes_xsl_mixing_spec:edit', '1', 2.00, 0, 1, 0, '1', 0, 'admin', NOW());
|
||||||
|
INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES ('177925970995543', '177925970995540', '删除', 2, 'xslmes:mes_xsl_mixing_spec:delete', '1', 3.00, 0, 1, 0, '1', 0, 'admin', NOW());
|
||||||
|
INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES ('177925970995544', '177925970995540', '批量删除', 2, 'xslmes:mes_xsl_mixing_spec:deleteBatch', '1', 4.00, 0, 1, 0, '1', 0, 'admin', NOW());
|
||||||
|
INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES ('177925970995545', '177925970995540', '导出', 2, 'xslmes:mes_xsl_mixing_spec:exportXls', '1', 5.00, 0, 1, 0, '1', 0, 'admin', NOW());
|
||||||
|
INSERT IGNORE INTO `sys_permission` (`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES ('177925970995546', '177925970995540', '导入', 2, 'xslmes:mes_xsl_mixing_spec:importExcel', '1', 6.00, 0, 1, 0, '1', 0, 'admin', NOW());
|
||||||
|
|
||||||
|
INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
|
||||||
|
SELECT REPLACE(UUID(), '-', ''), r.id, p.id, NULL, NOW(), '127.0.0.1'
|
||||||
|
FROM `sys_role` r
|
||||||
|
CROSS JOIN `sys_permission` p
|
||||||
|
WHERE r.`role_code` = 'admin'
|
||||||
|
AND p.`id` IN (
|
||||||
|
'177925970995540', '177925970995541', '177925970995542',
|
||||||
|
'177925970995543', '177925970995544', '177925970995545', '177925970995546'
|
||||||
|
)
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM `sys_role_permission` rp
|
||||||
|
WHERE rp.`role_id` = r.id AND rp.`permission_id` = p.id
|
||||||
|
);
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-- 分类字典:原辅材料子类增加「胶料」标记字段(幂等)
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
SET @db = DATABASE();
|
||||||
|
|
||||||
|
SET @sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'sys_category' AND COLUMN_NAME = 'is_rubber') = 0,
|
||||||
|
'ALTER TABLE `sys_category` ADD COLUMN `is_rubber` varchar(1) DEFAULT ''0'' COMMENT ''是否胶料 1是/0否'' AFTER `has_child`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- 天然胶、合成胶、再生胶默认标记为胶料
|
||||||
|
UPDATE `sys_category`
|
||||||
|
SET `is_rubber` = '1', `update_by` = 'admin', `update_time` = NOW()
|
||||||
|
WHERE `code` IN (
|
||||||
|
'XSLMES_MATERIAL_RAW_AUX_TRJ',
|
||||||
|
'XSLMES_MATERIAL_RAW_AUX_HCJ',
|
||||||
|
'XSLMES_MATERIAL_RAW_AUX_ZSJ'
|
||||||
|
);
|
||||||
@@ -56,6 +56,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 高层级业务弹窗(如混炼示方选料 z-index 1500)打开时,顶部提示需置于弹窗之上
|
||||||
|
.ant-message,
|
||||||
|
.ant-notification {
|
||||||
|
z-index: 2200 !important;
|
||||||
|
}
|
||||||
|
|
||||||
// =======================================
|
// =======================================
|
||||||
// ============ [sjl] 按钮组样式 ==========
|
// ============ [sjl] 按钮组样式 ==========
|
||||||
// =======================================
|
// =======================================
|
||||||
|
|||||||
@@ -11,11 +11,21 @@
|
|||||||
import { list as mixerList, queryById as queryMixerById } from '../MesMixerMaterial.api';
|
import { list as mixerList, queryById as queryMixerById } from '../MesMixerMaterial.api';
|
||||||
import { columns as mixerColumns, searchFormSchema as mixerSearch } from '../MesMixerMaterial.data';
|
import { columns as mixerColumns, searchFormSchema as mixerSearch } from '../MesMixerMaterial.data';
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
|
import {
|
||||||
|
loadMixingMaterialKindLookup,
|
||||||
|
resolveMixingMaterialKindFromLookup,
|
||||||
|
type MixerMaterialKindLookup,
|
||||||
|
} from '/@/views/xslmes/mesXslMixingSpec/MesXslMixingSpec.data';
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
|
|
||||||
const emit = defineEmits(['register', 'select']);
|
const emit = defineEmits(['register', 'select']);
|
||||||
const { createMessage } = useMessage();
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
const selectedRow = ref<Recordable | null>(null);
|
const selectedRow = ref<Recordable | null>(null);
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
|
const kindLookup = ref<MixerMaterialKindLookup | null>(null);
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
|
|
||||||
const [registerTable, { reload, getSelectRowKeys, getSelectRows, setSelectedRowKeys, clearSelectedRowKeys }] = useTable({
|
const [registerTable, { reload, getSelectRowKeys, getSelectRows, setSelectedRowKeys, clearSelectedRowKeys }] = useTable({
|
||||||
api: mixerList,
|
api: mixerList,
|
||||||
@@ -44,6 +54,9 @@
|
|||||||
selectedRow.value = null;
|
selectedRow.value = null;
|
||||||
clearSelectedRowKeys?.();
|
clearSelectedRowKeys?.();
|
||||||
setModalProps({ confirmLoading: false });
|
setModalProps({ confirmLoading: false });
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
|
kindLookup.value = await loadMixingMaterialKindLookup();
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
const mid = data?.mixerMaterialId as string | undefined;
|
const mid = data?.mixerMaterialId as string | undefined;
|
||||||
if (mid) {
|
if (mid) {
|
||||||
setSelectedRowKeys?.([mid]);
|
setSelectedRowKeys?.([mid]);
|
||||||
@@ -60,12 +73,13 @@
|
|||||||
reload();
|
reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
function buildKind(row: Recordable) {
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
const a = row.majorCategoryId_dictText || '';
|
function resolveMaterialKind(row: Recordable) {
|
||||||
const b = row.minorCategoryId_dictText || '';
|
const minorId = row?.minorCategoryId ? String(row.minorCategoryId) : '';
|
||||||
if (a && b) return `${a} / ${b}`;
|
const minorName = row?.minorCategoryId_dictText || '';
|
||||||
return a || b || '';
|
return resolveMixingMaterialKindFromLookup(kindLookup.value, undefined, minorId, minorName);
|
||||||
}
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
|
|
||||||
async function handleOk() {
|
async function handleOk() {
|
||||||
const keys = (getSelectRowKeys?.() || []) as string[];
|
const keys = (getSelectRowKeys?.() || []) as string[];
|
||||||
@@ -82,12 +96,19 @@
|
|||||||
createMessage.warning('请选择一条密炼物料');
|
createMessage.warning('请选择一条密炼物料');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
|
const materialKind = resolveMaterialKind(row);
|
||||||
|
if (!materialKind) {
|
||||||
|
createMessage.warning('未匹配到种类,请检查密炼物料种类配置');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】通用密炼物料选料弹窗种类改读配置表-----------
|
||||||
emit('select', {
|
emit('select', {
|
||||||
mixerMaterialId: row.id,
|
mixerMaterialId: row.id,
|
||||||
materialName: row.materialName || '',
|
materialName: row.materialName || '',
|
||||||
materialCode: row.materialCode || '',
|
materialCode: row.materialCode || '',
|
||||||
materialDesc: row.materialDesc || '',
|
materialDesc: row.materialDesc || '',
|
||||||
materialKind: buildKind(row),
|
materialKind,
|
||||||
minorCategoryId: row.minorCategoryId || '',
|
minorCategoryId: row.minorCategoryId || '',
|
||||||
majorCategoryText: row.majorCategoryId_dictText || '',
|
majorCategoryText: row.majorCategoryId_dictText || '',
|
||||||
minorCategoryText: row.minorCategoryId_dictText || '',
|
minorCategoryText: row.minorCategoryId_dictText || '',
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ import { BasicModal, useModalInner } from '/@/components/Modal';
|
|||||||
import { BasicForm, useForm } from '/@/components/Form';
|
import { BasicForm, useForm } from '/@/components/Form';
|
||||||
import { defHttp } from '/@/utils/http/axios';
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
import { loadTreeData } from '/@/views/system/category/category.api';
|
import { loadTreeData } from '/@/views/system/category/category.api';
|
||||||
|
import {
|
||||||
|
MATERIAL_RAW_AUX_CODE,
|
||||||
|
materialRawAuxCategoryId,
|
||||||
|
ensureMaterialCategoryContext,
|
||||||
|
isMaterialMinorCategory,
|
||||||
|
toIsRubberFlag,
|
||||||
|
fromIsRubberFlag,
|
||||||
|
} from '/@/views/system/category/category.constants';
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
import type { FormSchema } from '/@/components/Form';
|
import type { FormSchema } from '/@/components/Form';
|
||||||
import type { Recordable } from '/@/types/global';
|
import type { Recordable } from '/@/types/global';
|
||||||
@@ -34,6 +42,15 @@ const schemas: FormSchema[] = [
|
|||||||
required: true,
|
required: true,
|
||||||
componentProps: { maxlength: 50, placeholder: '请输入分类名称' },
|
componentProps: { maxlength: 50, placeholder: '请输入分类名称' },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: ' ',
|
||||||
|
field: 'isRubber',
|
||||||
|
component: 'Checkbox',
|
||||||
|
defaultValue: false,
|
||||||
|
renderComponentContent: '胶料',
|
||||||
|
colProps: { span: 24 },
|
||||||
|
ifShow: ({ values }) => isMaterialMinorCategory(values.pid),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const [registerForm, { resetFields, setFieldsValue, validate, updateSchema, scrollToField }] = useForm({
|
const [registerForm, { resetFields, setFieldsValue, validate, updateSchema, scrollToField }] = useForm({
|
||||||
@@ -64,10 +81,31 @@ async function buildPidTree(): Promise<Recordable[]> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function ensureMaterialRawAuxCategoryId() {
|
||||||
|
if (materialRawAuxCategoryId.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await defHttp.get(
|
||||||
|
{ url: '/sys/category/loadOne', params: { field: 'code', val: MATERIAL_RAW_AUX_CODE } },
|
||||||
|
{ isTransformResponse: false },
|
||||||
|
);
|
||||||
|
if (res?.success && res?.result?.id) {
|
||||||
|
materialRawAuxCategoryId.value = res.result.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSubmitValues(values: Recordable) {
|
||||||
|
const payload = { ...values };
|
||||||
|
payload.isRubber = isMaterialMinorCategory(payload.pid) ? toIsRubberFlag(payload.isRubber) : '0';
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
await resetFields();
|
await resetFields();
|
||||||
setModalProps({ confirmLoading: false });
|
setModalProps({ confirmLoading: false });
|
||||||
isUpdate.value = !!data?.isUpdate;
|
isUpdate.value = !!data?.isUpdate;
|
||||||
|
await ensureMaterialRawAuxCategoryId();
|
||||||
|
await ensureMaterialCategoryContext();
|
||||||
const tree = await buildPidTree();
|
const tree = await buildPidTree();
|
||||||
if (!tree.length) {
|
if (!tree.length) {
|
||||||
createMessage.warning('未加载到物料分类树,请确认分类字典根编码 XSLMES_MATERIAL 已存在');
|
createMessage.warning('未加载到物料分类树,请确认分类字典根编码 XSLMES_MATERIAL 已存在');
|
||||||
@@ -89,7 +127,7 @@ const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data
|
|||||||
|
|
||||||
if (unref(isUpdate) && data?.record?.id) {
|
if (unref(isUpdate) && data?.record?.id) {
|
||||||
const cat = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id: data.record.id } });
|
const cat = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id: data.record.id } });
|
||||||
await setFieldsValue({ id: cat.id, pid: cat.pid, name: cat.name });
|
await setFieldsValue({ id: cat.id, pid: cat.pid, name: cat.name, isRubber: fromIsRubberFlag(cat.isRubber) });
|
||||||
} else {
|
} else {
|
||||||
const pid = data?.parentId != null && data.parentId !== '' ? String(data.parentId) : '';
|
const pid = data?.parentId != null && data.parentId !== '' ? String(data.parentId) : '';
|
||||||
await setFieldsValue({ pid: pid || undefined, name: '' });
|
await setFieldsValue({ pid: pid || undefined, name: '' });
|
||||||
@@ -100,13 +138,13 @@ const title = computed(() => (unref(isUpdate) ? '编辑物料分类' : '新增
|
|||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
try {
|
try {
|
||||||
const values = await validate();
|
const values = normalizeSubmitValues(await validate());
|
||||||
setModalProps({ confirmLoading: true });
|
setModalProps({ confirmLoading: true });
|
||||||
if (unref(isUpdate)) {
|
if (unref(isUpdate)) {
|
||||||
const full = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id: values.id } });
|
const full = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id: values.id } });
|
||||||
await editMaterialSysCategory({ ...full, pid: values.pid, name: values.name });
|
await editMaterialSysCategory({ ...full, pid: values.pid, name: values.name, isRubber: values.isRubber });
|
||||||
} else {
|
} else {
|
||||||
await saveMaterialSysCategory({ pid: values.pid, name: values.name });
|
await saveMaterialSysCategory({ pid: values.pid, name: values.name, isRubber: values.isRubber });
|
||||||
}
|
}
|
||||||
closeModal();
|
closeModal();
|
||||||
emit('success');
|
emit('success');
|
||||||
|
|||||||
319
jeecgboot-vue3/src/views/system/category/category.constants.ts
Normal file
319
jeecgboot-vue3/src/views/system/category/category.constants.ts
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
import { getChildListBatch, loadTreeData } from './category.api';
|
||||||
|
|
||||||
|
/** MES 物料分类根编码 */
|
||||||
|
export const MATERIAL_ROOT_CODE = 'XSLMES_MATERIAL';
|
||||||
|
|
||||||
|
/** MES 物料分类 - 原辅材料编码(兼容旧逻辑) */
|
||||||
|
export const MATERIAL_RAW_AUX_CODE = 'XSLMES_MATERIAL_RAW_AUX';
|
||||||
|
|
||||||
|
/** 原辅材料分类节点 ID(运行时加载,兼容旧逻辑) */
|
||||||
|
export const materialRawAuxCategoryId = ref('');
|
||||||
|
|
||||||
|
/** MES 物料分类根节点 ID(运行时加载) */
|
||||||
|
export const materialRootCategoryId = ref('');
|
||||||
|
|
||||||
|
/** MES 物料大类节点 ID 集合(运行时加载) */
|
||||||
|
export const materialMajorCategoryIds = ref<Set<string>>(new Set());
|
||||||
|
|
||||||
|
let materialCategoryContextLoading: Promise<void> | null = null;
|
||||||
|
|
||||||
|
/** 加载 MES 物料分类上下文(根节点 + 大类 ID) */
|
||||||
|
export async function ensureMaterialCategoryContext(force = false) {
|
||||||
|
if (!force && materialRootCategoryId.value && materialMajorCategoryIds.value.size > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (materialCategoryContextLoading) {
|
||||||
|
await materialCategoryContextLoading;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
materialCategoryContextLoading = (async () => {
|
||||||
|
const rootRes = await defHttp.get(
|
||||||
|
{ url: '/sys/category/loadOne', params: { field: 'code', val: MATERIAL_ROOT_CODE } },
|
||||||
|
{ isTransformResponse: false },
|
||||||
|
);
|
||||||
|
if (rootRes?.success && rootRes?.result?.id) {
|
||||||
|
materialRootCategoryId.value = String(rootRes.result.id);
|
||||||
|
}
|
||||||
|
const auxRes = await defHttp.get(
|
||||||
|
{ url: '/sys/category/loadOne', params: { field: 'code', val: MATERIAL_RAW_AUX_CODE } },
|
||||||
|
{ isTransformResponse: false },
|
||||||
|
);
|
||||||
|
if (auxRes?.success && auxRes?.result?.id) {
|
||||||
|
materialRawAuxCategoryId.value = String(auxRes.result.id);
|
||||||
|
}
|
||||||
|
const majors = await loadTreeData({ async: false, pcode: MATERIAL_ROOT_CODE });
|
||||||
|
const majorIds = new Set<string>();
|
||||||
|
(Array.isArray(majors) ? majors : []).forEach((node) => {
|
||||||
|
const nodeKey = node?.key ?? node?.value ?? node?.id;
|
||||||
|
if (nodeKey != null) {
|
||||||
|
majorIds.add(String(nodeKey));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
materialMajorCategoryIds.value = majorIds;
|
||||||
|
})();
|
||||||
|
try {
|
||||||
|
await materialCategoryContextLoading;
|
||||||
|
} finally {
|
||||||
|
materialCategoryContextLoading = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否为原辅材料的直接子类(兼容旧逻辑) */
|
||||||
|
export function isMaterialRawAuxSubCategory(pid?: string) {
|
||||||
|
return !!materialRawAuxCategoryId.value && pid === materialRawAuxCategoryId.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否为 MES 物料小类(父节点为物料大类) */
|
||||||
|
export function isMaterialMinorCategory(pid?: string) {
|
||||||
|
if (!pid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return materialMajorCategoryIds.value.has(String(pid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 表单 Checkbox 布尔值 -> 数据库存储值 */
|
||||||
|
export function toIsRubberFlag(value: unknown) {
|
||||||
|
return value === true || value === '1' ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 数据库存储值 -> 表单 Checkbox 布尔值 */
|
||||||
|
export function fromIsRubberFlag(value: unknown) {
|
||||||
|
return value === '1' || value === 1 || value === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】统一加载MES物料分类树(大类+小类)-----------
|
||||||
|
export interface MesMaterialCategoryMinorItem {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
majorId: string;
|
||||||
|
majorName: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MesMaterialCategoryMajorItem {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
minors: MesMaterialCategoryMinorItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MesMaterialCategoryTreeLoadResult {
|
||||||
|
majors: MesMaterialCategoryMajorItem[];
|
||||||
|
minors: MesMaterialCategoryMinorItem[];
|
||||||
|
treeNodes: Recordable[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCategoryNodeKey(node: Recordable): string {
|
||||||
|
const key = node?.key ?? node?.value ?? node?.id;
|
||||||
|
return key != null && String(key) !== '' ? String(key) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCategoryNodeTitle(node: Recordable): string {
|
||||||
|
return String(node?.title ?? node?.name ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeTreeSelectNodes(nodes: unknown): Recordable[] {
|
||||||
|
if (Array.isArray(nodes)) {
|
||||||
|
return nodes as Recordable[];
|
||||||
|
}
|
||||||
|
if (nodes && typeof nodes === 'object') {
|
||||||
|
const payload = nodes as Recordable;
|
||||||
|
if (Array.isArray(payload.result)) {
|
||||||
|
return payload.result;
|
||||||
|
}
|
||||||
|
if (Array.isArray(payload.records)) {
|
||||||
|
return payload.records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载 MES 物料分类树:根下物料大类 + 各物料小类(供密炼物料/混炼示方选料复用) */
|
||||||
|
let mesMaterialCategoryTreeCache: MesMaterialCategoryTreeLoadResult | null = null;
|
||||||
|
let mesMaterialCategoryTreeLoading: Promise<MesMaterialCategoryTreeLoadResult> | null = null;
|
||||||
|
|
||||||
|
export function hasMesMaterialCategoryTreeCache() {
|
||||||
|
return !!(mesMaterialCategoryTreeCache?.minors?.length || mesMaterialCategoryTreeCache?.majors?.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearMesMaterialCategoryTreeCache() {
|
||||||
|
mesMaterialCategoryTreeCache = null;
|
||||||
|
mesMaterialCategoryTreeLoading = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadMesMaterialCategoryTreeData(forceReload = false): Promise<MesMaterialCategoryTreeLoadResult> {
|
||||||
|
if (!forceReload && mesMaterialCategoryTreeCache) {
|
||||||
|
return mesMaterialCategoryTreeCache;
|
||||||
|
}
|
||||||
|
if (!forceReload && mesMaterialCategoryTreeLoading) {
|
||||||
|
return mesMaterialCategoryTreeLoading;
|
||||||
|
}
|
||||||
|
mesMaterialCategoryTreeLoading = fetchMesMaterialCategoryTreeData()
|
||||||
|
.then((result) => {
|
||||||
|
if (result.minors.length || result.majors.length) {
|
||||||
|
mesMaterialCategoryTreeCache = result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
mesMaterialCategoryTreeLoading = null;
|
||||||
|
});
|
||||||
|
return mesMaterialCategoryTreeLoading;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchMesMaterialCategoryTreeData(): Promise<MesMaterialCategoryTreeLoadResult> {
|
||||||
|
// 优先 loadTreeRoot(与密炼物料列表页一致,已验证可用)
|
||||||
|
try {
|
||||||
|
const treeRes = await loadTreeData({ async: false, pcode: MATERIAL_ROOT_CODE });
|
||||||
|
const treeResult = buildMesMaterialCategoryTreeFromTreeSelect(normalizeTreeSelectNodes(treeRes));
|
||||||
|
if (treeResult.minors.length) {
|
||||||
|
if (!materialRootCategoryId.value) {
|
||||||
|
await ensureMaterialCategoryContext();
|
||||||
|
}
|
||||||
|
return treeResult;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// 继续走 batch 兜底
|
||||||
|
}
|
||||||
|
|
||||||
|
let rootId = materialRootCategoryId.value;
|
||||||
|
if (!rootId) {
|
||||||
|
try {
|
||||||
|
const root = await defHttp.get<Recordable>({
|
||||||
|
url: '/sys/category/loadOne',
|
||||||
|
params: { field: 'code', val: MATERIAL_ROOT_CODE },
|
||||||
|
});
|
||||||
|
if (root?.id) {
|
||||||
|
rootId = String(root.id);
|
||||||
|
materialRootCategoryId.value = rootId;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
rootId = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!rootId) {
|
||||||
|
return { majors: [], minors: [], treeNodes: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
let majorRecords: Recordable[] = [];
|
||||||
|
let minorRecords: Recordable[] = [];
|
||||||
|
try {
|
||||||
|
const majorBatch = await getChildListBatch({ parentIds: rootId });
|
||||||
|
if (majorBatch?.success === false) {
|
||||||
|
return { majors: [], minors: [], treeNodes: [] };
|
||||||
|
}
|
||||||
|
majorRecords = (majorBatch?.result?.records || majorBatch?.records || []) as Recordable[];
|
||||||
|
if (majorRecords.length) {
|
||||||
|
const majorIds = majorRecords.map((item) => String(item.id)).filter(Boolean).join(',');
|
||||||
|
if (majorIds) {
|
||||||
|
const minorBatch = await getChildListBatch({ parentIds: majorIds });
|
||||||
|
if (minorBatch?.success !== false) {
|
||||||
|
minorRecords = (minorBatch?.result?.records || minorBatch?.records || []) as Recordable[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return { majors: [], minors: [], treeNodes: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = buildMesMaterialCategoryTreeFromRecords(majorRecords, minorRecords);
|
||||||
|
materialMajorCategoryIds.value = new Set(result.majors.map((item) => item.id));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildMesMaterialCategoryTreeFromRecords(majorRecords: Recordable[], minorRecords: Recordable[]) {
|
||||||
|
const majorMap = new Map<string, { id: string; name: string; minors: MesMaterialCategoryMinorItem[] }>();
|
||||||
|
majorRecords.forEach((record) => {
|
||||||
|
const majorId = normalizeCategoryNodeKey(record);
|
||||||
|
if (!majorId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
majorMap.set(majorId, {
|
||||||
|
id: majorId,
|
||||||
|
name: normalizeCategoryNodeTitle(record),
|
||||||
|
minors: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
minorRecords.forEach((record) => {
|
||||||
|
const majorId = record?.pid != null ? String(record.pid) : '';
|
||||||
|
const minorId = normalizeCategoryNodeKey(record);
|
||||||
|
const major = majorMap.get(majorId);
|
||||||
|
if (!major || !minorId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
major.minors.push({
|
||||||
|
id: minorId,
|
||||||
|
name: normalizeCategoryNodeTitle(record),
|
||||||
|
majorId: major.id,
|
||||||
|
majorName: major.name,
|
||||||
|
label: major.name && normalizeCategoryNodeTitle(record)
|
||||||
|
? `${major.name} / ${normalizeCategoryNodeTitle(record)}`
|
||||||
|
: normalizeCategoryNodeTitle(record) || major.name,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const majors: MesMaterialCategoryMajorItem[] = [];
|
||||||
|
const minors: MesMaterialCategoryMinorItem[] = [];
|
||||||
|
const treeNodes: Recordable[] = [];
|
||||||
|
|
||||||
|
majorMap.forEach((major) => {
|
||||||
|
if (!major.minors.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
majors.push({ id: major.id, name: major.name, minors: major.minors });
|
||||||
|
minors.push(...major.minors);
|
||||||
|
treeNodes.push({
|
||||||
|
key: major.id,
|
||||||
|
title: major.name,
|
||||||
|
children: major.minors.map((minor) => ({ key: minor.id, title: minor.name })),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return { majors, minors, treeNodes };
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildMesMaterialCategoryTreeFromTreeSelect(majorRaw: Recordable[]) {
|
||||||
|
const majors: MesMaterialCategoryMajorItem[] = [];
|
||||||
|
const minors: MesMaterialCategoryMinorItem[] = [];
|
||||||
|
const treeNodes: Recordable[] = [];
|
||||||
|
|
||||||
|
majorRaw.forEach((major) => {
|
||||||
|
const majorId = normalizeCategoryNodeKey(major);
|
||||||
|
const majorName = normalizeCategoryNodeTitle(major);
|
||||||
|
if (!majorId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const majorMinors: MesMaterialCategoryMinorItem[] = [];
|
||||||
|
(Array.isArray(major.children) ? major.children : []).forEach((child) => {
|
||||||
|
const minorId = normalizeCategoryNodeKey(child);
|
||||||
|
const minorName = normalizeCategoryNodeTitle(child);
|
||||||
|
if (!minorId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const item: MesMaterialCategoryMinorItem = {
|
||||||
|
id: minorId,
|
||||||
|
name: minorName,
|
||||||
|
majorId,
|
||||||
|
majorName,
|
||||||
|
label: majorName && minorName ? `${majorName} / ${minorName}` : minorName || majorName,
|
||||||
|
};
|
||||||
|
majorMinors.push(item);
|
||||||
|
minors.push(item);
|
||||||
|
});
|
||||||
|
if (!majorMinors.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
majors.push({ id: majorId, name: majorName, minors: majorMinors });
|
||||||
|
treeNodes.push({
|
||||||
|
key: majorId,
|
||||||
|
title: majorName,
|
||||||
|
children: majorMinors.map((minor) => ({ key: minor.id, title: minor.name })),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
materialMajorCategoryIds.value = new Set(majors.map((item) => item.id));
|
||||||
|
return { majors, minors, treeNodes };
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】统一加载MES物料分类树(大类+小类)-----------
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { BasicColumn } from '/@/components/Table';
|
import { BasicColumn } from '/@/components/Table';
|
||||||
import { FormSchema } from '/@/components/Table';
|
import { FormSchema } from '/@/components/Table';
|
||||||
|
import { isMaterialMinorCategory } from './category.constants';
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [
|
export const columns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
@@ -73,4 +74,13 @@ export const formSchema: FormSchema[] = [
|
|||||||
placeholder: '留空将按规则自动生成(如 A01.A02)',
|
placeholder: '留空将按规则自动生成(如 A01.A02)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: ' ',
|
||||||
|
field: 'isRubber',
|
||||||
|
component: 'Checkbox',
|
||||||
|
defaultValue: false,
|
||||||
|
renderComponentContent: '胶料',
|
||||||
|
colProps: { span: 24 },
|
||||||
|
show: ({ values }) => isMaterialMinorCategory(values.pid),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -9,12 +9,41 @@
|
|||||||
import { BasicForm, useForm } from '/src/components/Form';
|
import { BasicForm, useForm } from '/src/components/Form';
|
||||||
import { formSchema } from '../category.data';
|
import { formSchema } from '../category.data';
|
||||||
import { loadTreeData, saveOrUpdateDict } from '../category.api';
|
import { loadTreeData, saveOrUpdateDict } from '../category.api';
|
||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
import {
|
||||||
|
MATERIAL_RAW_AUX_CODE,
|
||||||
|
materialRawAuxCategoryId,
|
||||||
|
ensureMaterialCategoryContext,
|
||||||
|
isMaterialMinorCategory,
|
||||||
|
toIsRubberFlag,
|
||||||
|
fromIsRubberFlag,
|
||||||
|
} from '../category.constants';
|
||||||
|
import type { Recordable } from '/@/types/global';
|
||||||
// 获取emit
|
// 获取emit
|
||||||
const emit = defineEmits(['register', 'success']);
|
const emit = defineEmits(['register', 'success']);
|
||||||
const isUpdate = ref(true);
|
const isUpdate = ref(true);
|
||||||
const expandedRowKeys = ref([]);
|
const expandedRowKeys = ref([]);
|
||||||
const treeData = ref([]);
|
const treeData = ref([]);
|
||||||
const isSubAdd = ref(false);
|
const isSubAdd = ref(false);
|
||||||
|
|
||||||
|
async function ensureMaterialRawAuxCategoryId() {
|
||||||
|
if (materialRawAuxCategoryId.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await defHttp.get(
|
||||||
|
{ url: '/sys/category/loadOne', params: { field: 'code', val: MATERIAL_RAW_AUX_CODE } },
|
||||||
|
{ isTransformResponse: false },
|
||||||
|
);
|
||||||
|
if (res?.success && res?.result?.id) {
|
||||||
|
materialRawAuxCategoryId.value = res.result.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSubmitValues(values: Recordable) {
|
||||||
|
const payload = { ...values };
|
||||||
|
payload.isRubber = isMaterialMinorCategory(payload.pid) ? toIsRubberFlag(payload.isRubber) : '0';
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
//表单配置
|
//表单配置
|
||||||
const [registerForm, { resetFields, setFieldsValue, validate, updateSchema }] = useForm({
|
const [registerForm, { resetFields, setFieldsValue, validate, updateSchema }] = useForm({
|
||||||
schemas: formSchema,
|
schemas: formSchema,
|
||||||
@@ -35,12 +64,15 @@
|
|||||||
expandedRowKeys.value = [];
|
expandedRowKeys.value = [];
|
||||||
setModalProps({ confirmLoading: false, minHeight: 80 });
|
setModalProps({ confirmLoading: false, minHeight: 80 });
|
||||||
isUpdate.value = !!data?.isUpdate;
|
isUpdate.value = !!data?.isUpdate;
|
||||||
|
await ensureMaterialRawAuxCategoryId();
|
||||||
|
await ensureMaterialCategoryContext();
|
||||||
// 代码逻辑说明: 分类字典data.record为空报错------------
|
// 代码逻辑说明: 分类字典data.record为空报错------------
|
||||||
isSubAdd.value = !data?.isUpdate && data.record && data.record.id;
|
isSubAdd.value = !data?.isUpdate && data.record && data.record.id;
|
||||||
if (data?.record) {
|
if (data?.record) {
|
||||||
//表单赋值
|
//表单赋值
|
||||||
await setFieldsValue({
|
await setFieldsValue({
|
||||||
...data.record,
|
...data.record,
|
||||||
|
isRubber: fromIsRubberFlag(data.record.isRubber),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//父级节点树信息
|
//父级节点树信息
|
||||||
@@ -76,6 +108,7 @@
|
|||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
try {
|
try {
|
||||||
let values = await validate();
|
let values = await validate();
|
||||||
|
values = normalizeSubmitValues(values);
|
||||||
setModalProps({ confirmLoading: true });
|
setModalProps({ confirmLoading: true });
|
||||||
//提交表单
|
//提交表单
|
||||||
await saveOrUpdateDict(values, isUpdate.value);
|
await saveOrUpdateDict(values, isUpdate.value);
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal v-bind="$attrs" title="选择机台(可多选)" :width="1000" @register="registerModal" @ok="handleOk">
|
||||||
|
<BasicTable @register="registerTable" />
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { BasicTable, useTable } from '/@/components/Table';
|
||||||
|
import { list } from '/@/views/xslmes/mesXslEquipmentLedger/MesXslEquipmentLedger.api';
|
||||||
|
|
||||||
|
const emit = defineEmits(['register', 'select']);
|
||||||
|
|
||||||
|
const selectedRows = ref<Recordable[]>([]);
|
||||||
|
|
||||||
|
function handleSelectionChange(_keys: string[], rows: Recordable[]) {
|
||||||
|
selectedRows.value = rows || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const [registerTable, { reload, getSelectRows, setSelectedRowKeys, clearSelectedRowKeys }] = useTable({
|
||||||
|
api: list,
|
||||||
|
columns: [
|
||||||
|
{ title: '设备名称', dataIndex: 'equipmentName', width: 160 },
|
||||||
|
{ title: '设备编号', dataIndex: 'equipmentCode', width: 140 },
|
||||||
|
{ title: '有效体积', dataIndex: 'effectiveVolume', width: 100 },
|
||||||
|
{ title: '设备类别', dataIndex: 'equipmentCategoryName', width: 120 },
|
||||||
|
{ title: '设备类型', dataIndex: 'equipmentTypeName', width: 120 },
|
||||||
|
],
|
||||||
|
rowKey: 'id',
|
||||||
|
useSearchForm: true,
|
||||||
|
formConfig: {
|
||||||
|
labelWidth: 90,
|
||||||
|
schemas: [
|
||||||
|
{ label: '设备名称', field: 'equipmentName', component: 'Input', colProps: { span: 8 } },
|
||||||
|
{ label: '设备编号', field: 'equipmentCode', component: 'Input', colProps: { span: 8 } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
pagination: { pageSize: 10 },
|
||||||
|
canResize: false,
|
||||||
|
showIndexColumn: false,
|
||||||
|
immediate: true,
|
||||||
|
rowSelection: {
|
||||||
|
type: 'checkbox',
|
||||||
|
columnWidth: 48,
|
||||||
|
onChange: handleSelectionChange,
|
||||||
|
},
|
||||||
|
clickToRowSelect: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
|
selectedRows.value = [];
|
||||||
|
clearSelectedRowKeys?.();
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
const preset = (data?.selectedMachines || []) as Array<{ machineId?: string }>;
|
||||||
|
const keys = preset.map((m) => m.machineId).filter(Boolean) as string[];
|
||||||
|
if (keys.length) {
|
||||||
|
setSelectedRowKeys?.(keys);
|
||||||
|
}
|
||||||
|
reload();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleOk() {
|
||||||
|
const rows = ((getSelectRows?.() || []) as Recordable[]).length
|
||||||
|
? (getSelectRows?.() || []) as Recordable[]
|
||||||
|
: selectedRows.value;
|
||||||
|
const machines = rows
|
||||||
|
.filter((r) => r?.id)
|
||||||
|
.map((r) => ({
|
||||||
|
machineId: r.id,
|
||||||
|
machineName: r.equipmentName || '',
|
||||||
|
machineCode: r.equipmentCode || '',
|
||||||
|
}));
|
||||||
|
emit('select', machines);
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!row?.id) {
|
if (!row?.id) {
|
||||||
emit('select', { equipmentLedgerId: '', equipmentName: '', equipmentCode: '' });
|
emit('select', { equipmentLedgerId: '', equipmentName: '', equipmentCode: '', effectiveVolume: '' });
|
||||||
closeModal();
|
closeModal();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -87,6 +87,7 @@
|
|||||||
equipmentLedgerId: row.id,
|
equipmentLedgerId: row.id,
|
||||||
equipmentName: row.equipmentName || '',
|
equipmentName: row.equipmentName || '',
|
||||||
equipmentCode: row.equipmentCode || '',
|
equipmentCode: row.equipmentCode || '',
|
||||||
|
effectiveVolume: row.effectiveVolume || '',
|
||||||
});
|
});
|
||||||
closeModal();
|
closeModal();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ enum Api {
|
|||||||
generateRubberCode = '/xslmes/mesXslFormulaSpec/generateRubberCode',
|
generateRubberCode = '/xslmes/mesXslFormulaSpec/generateRubberCode',
|
||||||
getRubberContentSetting = '/xslmes/mesXslFormulaSpec/getRubberContentSetting',
|
getRubberContentSetting = '/xslmes/mesXslFormulaSpec/getRubberContentSetting',
|
||||||
saveRubberContentSetting = '/xslmes/mesXslFormulaSpec/saveRubberContentSetting',
|
saveRubberContentSetting = '/xslmes/mesXslFormulaSpec/saveRubberContentSetting',
|
||||||
|
buildMixingGeneratePreview = '/xslmes/mesXslFormulaSpec/buildMixingGeneratePreview',
|
||||||
|
generateMixingSpec = '/xslmes/mesXslFormulaSpec/generateMixingSpec',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getExportUrl = Api.exportXls;
|
export const getExportUrl = Api.exportXls;
|
||||||
@@ -41,3 +43,12 @@ export const batchDelete = (params, handleSuccess) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const saveOrUpdate = (params, isUpdate) => defHttp.post({ url: isUpdate ? Api.edit : Api.save, params });
|
export const saveOrUpdate = (params, isUpdate) => defHttp.post({ url: isUpdate ? Api.edit : Api.save, params });
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方-----------
|
||||||
|
export const buildMixingGeneratePreview = (params) =>
|
||||||
|
defHttp.get({ url: Api.buildMixingGeneratePreview, params }, { successMessageMode: 'none' });
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】批量生成混炼示方延长超时避免误报失败-----------
|
||||||
|
export const generateMixingSpec = (params) =>
|
||||||
|
defHttp.post({ url: Api.generateMixingSpec, params, timeout: 120 * 1000 });
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】批量生成混炼示方延长超时避免误报失败-----------
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A38】配合示方生成混炼示方-----------
|
||||||
|
|||||||
@@ -36,27 +36,40 @@
|
|||||||
</a-button>
|
</a-button>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
|
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
v-auth="'xslmes:mes_xsl_mixing_spec:add'"
|
||||||
|
preIcon="ant-design:thunderbolt-outlined"
|
||||||
|
@click="handleGenerateMixing"
|
||||||
|
>
|
||||||
|
生成混炼示方
|
||||||
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
<template #action="{ record }">
|
<template #action="{ record }">
|
||||||
<TableAction :actions="getTableActions(record)" :dropDownActions="getDropDownAction(record)" />
|
<TableAction :actions="getTableActions(record)" :dropDownActions="getDropDownAction(record)" />
|
||||||
</template>
|
</template>
|
||||||
</BasicTable>
|
</BasicTable>
|
||||||
<MesXslFormulaSpecModal @register="registerModal" @success="handleSuccess" />
|
<MesXslFormulaSpecModal @register="registerModal" @success="handleSuccess" />
|
||||||
|
<MesXslFormulaGenerateMixingModal @register="registerGenerateMixingModal" @success="handleGenerateMixingSuccess" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" name="xslmes-mesXslFormulaSpec" setup>
|
<script lang="ts" name="xslmes-mesXslFormulaSpec" setup>
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
import { BasicTable, TableAction } from '/@/components/Table';
|
import { BasicTable, TableAction } from '/@/components/Table';
|
||||||
import { useModal } from '/@/components/Modal';
|
import { useModal } from '/@/components/Modal';
|
||||||
import { useListPage } from '/@/hooks/system/useListPage';
|
import { useListPage } from '/@/hooks/system/useListPage';
|
||||||
import Icon from '/@/components/Icon';
|
import Icon from '/@/components/Icon';
|
||||||
import MesXslFormulaSpecModal from './components/MesXslFormulaSpecModal.vue';
|
import MesXslFormulaSpecModal from './components/MesXslFormulaSpecModal.vue';
|
||||||
|
import MesXslFormulaGenerateMixingModal from './components/MesXslFormulaGenerateMixingModal.vue';
|
||||||
import { columns, searchFormSchema, superQuerySchema } from './MesXslFormulaSpec.data';
|
import { columns, searchFormSchema, superQuerySchema } from './MesXslFormulaSpec.data';
|
||||||
import { list, deleteOne, batchDelete, getExportUrl, getImportUrl } from './MesXslFormulaSpec.api';
|
import { list, deleteOne, batchDelete, getExportUrl, getImportUrl } from './MesXslFormulaSpec.api';
|
||||||
|
|
||||||
|
const { createMessage } = useMessage();
|
||||||
const queryParam = reactive<any>({});
|
const queryParam = reactive<any>({});
|
||||||
const [registerModal, { openModal }] = useModal();
|
const [registerModal, { openModal }] = useModal();
|
||||||
|
const [registerGenerateMixingModal, { openModal: openGenerateMixingModal }] = useModal();
|
||||||
|
|
||||||
const { tableContext, onExportXls, onImportXls } = useListPage({
|
const { tableContext, onExportXls, onImportXls } = useListPage({
|
||||||
tableProps: {
|
tableProps: {
|
||||||
@@ -125,6 +138,19 @@
|
|||||||
selectedRowKeys.value = [];
|
selectedRowKeys.value = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleGenerateMixing() {
|
||||||
|
const keys = selectedRowKeys.value || [];
|
||||||
|
if (keys.length !== 1) {
|
||||||
|
createMessage.warning('请勾选一条配合示方数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openGenerateMixingModal(true, { formulaSpecId: keys[0] });
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGenerateMixingSuccess() {
|
||||||
|
selectedRowKeys.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
function canEdit(record: Recordable) {
|
function canEdit(record: Recordable) {
|
||||||
return !record?.status || record.status === 'compile';
|
return !record?.status || record.status === 'compile';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
v-bind="$attrs"
|
||||||
|
title="生成混炼示方"
|
||||||
|
:width="880"
|
||||||
|
destroyOnClose
|
||||||
|
@register="registerModal"
|
||||||
|
@ok="handleConfirm"
|
||||||
|
>
|
||||||
|
<a-spin :spinning="loading">
|
||||||
|
<div v-if="rubberName" class="generate-mixing-tip">
|
||||||
|
胶料名称:<strong>{{ rubberName }}</strong>,混合段数:<strong>{{ mixingStages }}</strong>,确认后将按「预览行 × 机台」生成混炼示方。
|
||||||
|
</div>
|
||||||
|
<a-table
|
||||||
|
:columns="tableColumns"
|
||||||
|
:data-source="tableRows"
|
||||||
|
:pagination="false"
|
||||||
|
row-key="rowKey"
|
||||||
|
size="small"
|
||||||
|
bordered
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.dataIndex === 'machines'">
|
||||||
|
<div class="machine-cell">
|
||||||
|
<a-input
|
||||||
|
:value="formatMachineNames(record.machines)"
|
||||||
|
readonly
|
||||||
|
placeholder="请点击选择机台(可多选)"
|
||||||
|
class="machine-picker-input"
|
||||||
|
@click="openMachinePicker(record)"
|
||||||
|
/>
|
||||||
|
<a-button type="link" size="small" @click="openMachinePicker(record)">选择</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<div v-if="totalGenerateCount > 0" class="generate-mixing-summary">
|
||||||
|
预计生成 <strong>{{ totalGenerateCount }}</strong> 条混炼示方
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
<MesXslEquipmentLedgerMultiSelectModal @register="registerMachineModal" @select="onMachineSelect" />
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { BasicModal, useModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import MesXslEquipmentLedgerMultiSelectModal from '/@/views/xslmes/mesXslEquipInspectConfig/components/MesXslEquipmentLedgerMultiSelectModal.vue';
|
||||||
|
import { buildMixingGeneratePreview, generateMixingSpec } from '../MesXslFormulaSpec.api';
|
||||||
|
|
||||||
|
const emit = defineEmits(['register', 'success']);
|
||||||
|
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
const loading = ref(false);
|
||||||
|
const formulaSpecId = ref('');
|
||||||
|
const rubberName = ref('');
|
||||||
|
const mixingStages = ref(0);
|
||||||
|
const tableRows = ref<Recordable[]>([]);
|
||||||
|
const editingRowKey = ref<number | null>(null);
|
||||||
|
|
||||||
|
function formatStageCountText(record: Recordable) {
|
||||||
|
const current = record?.stageIndex;
|
||||||
|
const total = mixingStages.value;
|
||||||
|
if (total > 0) {
|
||||||
|
return `${current ?? ''}/${total}`;
|
||||||
|
}
|
||||||
|
return current != null ? String(current) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableColumns = [
|
||||||
|
{ title: '示方编号', dataIndex: 'specCode', width: 220 },
|
||||||
|
{ title: '段数', dataIndex: 'stageIndex', width: 72, customRender: ({ record }) => formatStageCountText(record) },
|
||||||
|
{ title: '机台', dataIndex: 'machines' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const totalGenerateCount = computed(() =>
|
||||||
|
tableRows.value.reduce((sum, row) => sum + (row.machines?.length || 0), 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
const [registerMachineModal, { openModal: openMachineModalInner }] = useModal();
|
||||||
|
|
||||||
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
|
formulaSpecId.value = data?.formulaSpecId || '';
|
||||||
|
tableRows.value = [];
|
||||||
|
rubberName.value = '';
|
||||||
|
mixingStages.value = 0;
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
if (!formulaSpecId.value) {
|
||||||
|
createMessage.warning('未指定配合示方');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const preview = await buildMixingGeneratePreview({ formulaSpecId: formulaSpecId.value });
|
||||||
|
rubberName.value = preview?.rubberName || '';
|
||||||
|
mixingStages.value = preview?.mixingStages || 0;
|
||||||
|
tableRows.value = (preview?.items || []).map((item: Recordable) => ({
|
||||||
|
rowKey: item.rowKey,
|
||||||
|
specCode: item.specCode,
|
||||||
|
stageIndex: item.stageIndex,
|
||||||
|
aSegmentIndex: item.aSegmentIndex,
|
||||||
|
stepType: item.stepType,
|
||||||
|
machines: [],
|
||||||
|
}));
|
||||||
|
if (!tableRows.value.length) {
|
||||||
|
createMessage.warning('无可生成的混炼段,请检查混合段数');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function formatMachineNames(machines: Recordable[] = []) {
|
||||||
|
return machines.map((m) => m.machineName).filter(Boolean).join('、');
|
||||||
|
}
|
||||||
|
|
||||||
|
function openMachinePicker(record: Recordable) {
|
||||||
|
editingRowKey.value = record.rowKey;
|
||||||
|
openMachineModalInner(true, { selectedMachines: record.machines || [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMachineSelect(machines: Recordable[]) {
|
||||||
|
const key = editingRowKey.value;
|
||||||
|
if (key == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const row = tableRows.value.find((r) => r.rowKey === key);
|
||||||
|
if (row) {
|
||||||
|
row.machines = machines || [];
|
||||||
|
}
|
||||||
|
editingRowKey.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleConfirm() {
|
||||||
|
if (!formulaSpecId.value) {
|
||||||
|
createMessage.warning('未指定配合示方');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!tableRows.value.length) {
|
||||||
|
createMessage.warning('无可生成的混炼段');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const emptyMachine = tableRows.value.find((r) => !r.machines?.length);
|
||||||
|
if (emptyMachine) {
|
||||||
|
createMessage.warning(`请为示方「${emptyMachine.specCode}」选择机台`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setModalProps({ confirmLoading: true });
|
||||||
|
try {
|
||||||
|
const res = await generateMixingSpec({
|
||||||
|
formulaSpecId: formulaSpecId.value,
|
||||||
|
rows: tableRows.value.map((r) => ({
|
||||||
|
specCode: r.specCode,
|
||||||
|
stageIndex: r.stageIndex,
|
||||||
|
aSegmentIndex: r.aSegmentIndex,
|
||||||
|
stepType: r.stepType,
|
||||||
|
machines: (r.machines || []).map((m: Recordable) => ({
|
||||||
|
machineId: m.machineId,
|
||||||
|
machineName: m.machineName,
|
||||||
|
})),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
const count = Number(res?.count ?? 0);
|
||||||
|
createMessage.success(count > 0 ? `成功生成 ${count} 条混炼示方` : '生成成功');
|
||||||
|
closeModal();
|
||||||
|
emit('success');
|
||||||
|
} finally {
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.generate-mixing-tip {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
}
|
||||||
|
.machine-cell {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
.machine-picker-input {
|
||||||
|
flex: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.generate-mixing-summary {
|
||||||
|
margin-top: 12px;
|
||||||
|
text-align: right;
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,6 +8,17 @@
|
|||||||
@register="registerModal"
|
@register="registerModal"
|
||||||
@ok="handleSubmit"
|
@ok="handleSubmit"
|
||||||
>
|
>
|
||||||
|
<template #insertFooter>
|
||||||
|
<a-button
|
||||||
|
v-if="showGenerateMixingBtn"
|
||||||
|
type="primary"
|
||||||
|
v-auth="'xslmes:mes_xsl_mixing_spec:add'"
|
||||||
|
preIcon="ant-design:thunderbolt-outlined"
|
||||||
|
@click="handleGenerateMixing"
|
||||||
|
>
|
||||||
|
生成混炼示方
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="formula-spec-modal-title">{{ title }}</span>
|
<span class="formula-spec-modal-title">{{ title }}</span>
|
||||||
<a-tooltip title="含胶率物料小类设置">
|
<a-tooltip title="含胶率物料小类设置">
|
||||||
@@ -390,6 +401,7 @@
|
|||||||
@getSelectResult="onIssueDeptSelect"
|
@getSelectResult="onIssueDeptSelect"
|
||||||
/>
|
/>
|
||||||
<MesXslFormulaRubberContentSettingModal @register="registerRubberContentSettingModal" @success="onRubberContentSettingSaved" />
|
<MesXslFormulaRubberContentSettingModal @register="registerRubberContentSettingModal" @success="onRubberContentSettingSaved" />
|
||||||
|
<MesXslFormulaGenerateMixingModal @register="registerGenerateMixingModal" />
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -439,6 +451,7 @@
|
|||||||
} from '../MesXslFormulaSpec.data';
|
} from '../MesXslFormulaSpec.data';
|
||||||
import { saveOrUpdate, queryById, generateRubberCode as generateRubberCodeApi, getRubberContentSetting } from '../MesXslFormulaSpec.api';
|
import { saveOrUpdate, queryById, generateRubberCode as generateRubberCodeApi, getRubberContentSetting } from '../MesXslFormulaSpec.api';
|
||||||
import MesXslFormulaRubberContentSettingModal from './MesXslFormulaRubberContentSettingModal.vue';
|
import MesXslFormulaRubberContentSettingModal from './MesXslFormulaRubberContentSettingModal.vue';
|
||||||
|
import MesXslFormulaGenerateMixingModal from './MesXslFormulaGenerateMixingModal.vue';
|
||||||
import MesXslFormulaLineColumnSetting from './MesXslFormulaLineColumnSetting.vue';
|
import MesXslFormulaLineColumnSetting from './MesXslFormulaLineColumnSetting.vue';
|
||||||
import { queryById as queryMixerById } from '/@/views/mes/material/MesMixerMaterial.api';
|
import { queryById as queryMixerById } from '/@/views/mes/material/MesMixerMaterial.api';
|
||||||
import { buildUUID } from '/@/utils/uuid';
|
import { buildUUID } from '/@/utils/uuid';
|
||||||
@@ -518,6 +531,7 @@
|
|||||||
const [registerIssueNumberModal, { openModal: openIssueNumberModalInner }] = useModal();
|
const [registerIssueNumberModal, { openModal: openIssueNumberModalInner }] = useModal();
|
||||||
const [registerIssueDeptModal, { openModal: openIssueDeptModalInner }] = useModal();
|
const [registerIssueDeptModal, { openModal: openIssueDeptModalInner }] = useModal();
|
||||||
const [registerRubberContentSettingModal, { openModal: openRubberContentSettingModal }] = useModal();
|
const [registerRubberContentSettingModal, { openModal: openRubberContentSettingModal }] = useModal();
|
||||||
|
const [registerGenerateMixingModal, { openModal: openGenerateMixingModal }] = useModal();
|
||||||
const issueDeptPickerValue = ref<string>('');
|
const issueDeptPickerValue = ref<string>('');
|
||||||
const rubberMaterialPickerId = ref<string>('');
|
const rubberMaterialPickerId = ref<string>('');
|
||||||
const mixerPsCompilePickerId = ref<string>('');
|
const mixerPsCompilePickerId = ref<string>('');
|
||||||
@@ -1172,6 +1186,19 @@
|
|||||||
return !unref(isUpdate) ? '新增配合示方' : '编辑配合示方';
|
return !unref(isUpdate) ? '新增配合示方' : '编辑配合示方';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const showGenerateMixingBtn = computed(
|
||||||
|
() => !showFooterFlag.value && unref(isUpdate) && !!loadedMainRecord.value?.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
function handleGenerateMixing() {
|
||||||
|
const id = loadedMainRecord.value?.id;
|
||||||
|
if (!id) {
|
||||||
|
createMessage.warning('请先保存配合示方');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openGenerateMixingModal(true, { formulaSpecId: id });
|
||||||
|
}
|
||||||
|
|
||||||
async function handleLineValueChange(event) {
|
async function handleLineValueChange(event) {
|
||||||
const { row, column } = event || {};
|
const { row, column } = event || {};
|
||||||
if (!row || !column) {
|
if (!row || !column) {
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal v-bind="$attrs" title="选择密炼机动作" :width="960" @register="registerModal" @ok="handleOk">
|
||||||
|
<BasicTable @register="registerTable" />
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { BasicTable, useTable } from '/@/components/Table';
|
||||||
|
import { list, queryById } from '../MesXslMixerAction.api';
|
||||||
|
import { columns as actionColumns, searchFormSchema } from '../MesXslMixerAction.data';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
|
||||||
|
const emit = defineEmits(['register', 'select']);
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
|
const equipmentId = ref('');
|
||||||
|
const selectedRow = ref<Recordable | null>(null);
|
||||||
|
|
||||||
|
const [registerTable, { reload, getSelectRowKeys, getSelectRows, setSelectedRowKeys, clearSelectedRowKeys }] = useTable({
|
||||||
|
api: list,
|
||||||
|
columns: actionColumns,
|
||||||
|
rowKey: 'id',
|
||||||
|
useSearchForm: true,
|
||||||
|
formConfig: {
|
||||||
|
labelWidth: 90,
|
||||||
|
schemas: searchFormSchema,
|
||||||
|
},
|
||||||
|
pagination: { pageSize: 10 },
|
||||||
|
canResize: false,
|
||||||
|
showIndexColumn: false,
|
||||||
|
immediate: true,
|
||||||
|
beforeFetch: (params) => ({
|
||||||
|
...params,
|
||||||
|
equipmentId: equipmentId.value || undefined,
|
||||||
|
}),
|
||||||
|
rowSelection: {
|
||||||
|
type: 'radio',
|
||||||
|
columnWidth: 48,
|
||||||
|
onChange: (_keys, rows) => {
|
||||||
|
selectedRow.value = rows?.[0] ?? null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
clickToRowSelect: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
|
equipmentId.value = (data?.equipmentId as string) || '';
|
||||||
|
selectedRow.value = null;
|
||||||
|
clearSelectedRowKeys?.();
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
const actionId = data?.actionId as string | undefined;
|
||||||
|
if (actionId) {
|
||||||
|
setSelectedRowKeys?.([actionId]);
|
||||||
|
try {
|
||||||
|
const raw = await queryById({ id: actionId });
|
||||||
|
const row = (raw as Recordable)?.id != null ? raw : (raw as Recordable)?.result;
|
||||||
|
if (row) {
|
||||||
|
selectedRow.value = row;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reload();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleOk() {
|
||||||
|
const keys = (getSelectRowKeys?.() || []) as string[];
|
||||||
|
let row = selectedRow.value || ((getSelectRows?.() || []) as Recordable[])[0];
|
||||||
|
if (!row && keys.length) {
|
||||||
|
try {
|
||||||
|
const raw = await queryById({ id: keys[0] });
|
||||||
|
row = (raw as Recordable)?.id != null ? raw : (raw as Recordable)?.result;
|
||||||
|
} catch {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!row?.id) {
|
||||||
|
createMessage.warning('请选择一条密炼机动作');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit('select', {
|
||||||
|
actionId: row.id,
|
||||||
|
actionName: row.actionName || '',
|
||||||
|
actionCode: row.actionCode || '',
|
||||||
|
});
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal v-bind="$attrs" title="选择密炼机条件" :width="960" @register="registerModal" @ok="handleOk">
|
||||||
|
<BasicTable @register="registerTable" />
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { BasicTable, useTable } from '/@/components/Table';
|
||||||
|
import { list, queryById } from '../MesXslMixerCondition.api';
|
||||||
|
import { columns as conditionColumns, searchFormSchema } from '../MesXslMixerCondition.data';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
|
||||||
|
const emit = defineEmits(['register', 'select']);
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
|
const equipmentId = ref('');
|
||||||
|
const selectedRow = ref<Recordable | null>(null);
|
||||||
|
|
||||||
|
const [registerTable, { reload, getSelectRowKeys, getSelectRows, setSelectedRowKeys, clearSelectedRowKeys }] = useTable({
|
||||||
|
api: list,
|
||||||
|
columns: conditionColumns.slice(0, 4),
|
||||||
|
rowKey: 'id',
|
||||||
|
useSearchForm: true,
|
||||||
|
formConfig: {
|
||||||
|
labelWidth: 90,
|
||||||
|
schemas: searchFormSchema,
|
||||||
|
},
|
||||||
|
pagination: { pageSize: 10 },
|
||||||
|
canResize: false,
|
||||||
|
showIndexColumn: false,
|
||||||
|
immediate: true,
|
||||||
|
beforeFetch: (params) => ({
|
||||||
|
...params,
|
||||||
|
equipmentId: equipmentId.value || undefined,
|
||||||
|
}),
|
||||||
|
rowSelection: {
|
||||||
|
type: 'radio',
|
||||||
|
columnWidth: 48,
|
||||||
|
onChange: (_keys, rows) => {
|
||||||
|
selectedRow.value = rows?.[0] ?? null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
clickToRowSelect: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
|
equipmentId.value = (data?.equipmentId as string) || '';
|
||||||
|
selectedRow.value = null;
|
||||||
|
clearSelectedRowKeys?.();
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
const conditionId = data?.conditionId as string | undefined;
|
||||||
|
if (conditionId) {
|
||||||
|
setSelectedRowKeys?.([conditionId]);
|
||||||
|
try {
|
||||||
|
const raw = await queryById({ id: conditionId });
|
||||||
|
const row = (raw as Recordable)?.id != null ? raw : (raw as Recordable)?.result;
|
||||||
|
if (row) {
|
||||||
|
selectedRow.value = row;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reload();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleOk() {
|
||||||
|
const keys = (getSelectRowKeys?.() || []) as string[];
|
||||||
|
let row = selectedRow.value || ((getSelectRows?.() || []) as Recordable[])[0];
|
||||||
|
if (!row && keys.length) {
|
||||||
|
try {
|
||||||
|
const raw = await queryById({ id: keys[0] });
|
||||||
|
row = (raw as Recordable)?.id != null ? raw : (raw as Recordable)?.result;
|
||||||
|
} catch {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!row?.id) {
|
||||||
|
createMessage.warning('请选择一条密炼机条件');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit('select', {
|
||||||
|
conditionId: row.id,
|
||||||
|
conditionName: row.conditionName || '',
|
||||||
|
conditionCode: row.conditionCode || '',
|
||||||
|
});
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
|
||||||
|
enum Api {
|
||||||
|
list = '/xslmes/mesXslMixerMaterialKindCfg/list',
|
||||||
|
save = '/xslmes/mesXslMixerMaterialKindCfg/add',
|
||||||
|
edit = '/xslmes/mesXslMixerMaterialKindCfg/edit',
|
||||||
|
addBatch = '/xslmes/mesXslMixerMaterialKindCfg/addBatch',
|
||||||
|
expandLines = '/xslmes/mesXslMixerMaterialKindCfg/expandLines',
|
||||||
|
deleteOne = '/xslmes/mesXslMixerMaterialKindCfg/delete',
|
||||||
|
deleteBatch = '/xslmes/mesXslMixerMaterialKindCfg/deleteBatch',
|
||||||
|
importExcel = '/xslmes/mesXslMixerMaterialKindCfg/importExcel',
|
||||||
|
exportXls = '/xslmes/mesXslMixerMaterialKindCfg/exportXls',
|
||||||
|
queryById = '/xslmes/mesXslMixerMaterialKindCfg/queryById',
|
||||||
|
kindLookup = '/xslmes/mesXslMixerMaterialKindCfg/kindLookup',
|
||||||
|
resolveKind = '/xslmes/mesXslMixerMaterialKindCfg/resolveKind',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||||
|
|
||||||
|
export const queryById = (params) => defHttp.get({ url: Api.queryById, params });
|
||||||
|
|
||||||
|
export const loadKindLookup = (params?) => defHttp.get({ url: Api.kindLookup, params });
|
||||||
|
|
||||||
|
export const resolveKind = (params) => defHttp.get({ url: Api.resolveKind, params });
|
||||||
|
|
||||||
|
export const expandLines = (params) => defHttp.get({ url: Api.expandLines, params });
|
||||||
|
|
||||||
|
export const addBatch = (params) => defHttp.post({ url: Api.addBatch, params }, { successMessageMode: 'none' });
|
||||||
|
|
||||||
|
export const deleteOne = (params, handleSuccess) =>
|
||||||
|
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => handleSuccess());
|
||||||
|
|
||||||
|
export const batchDelete = (params, handleSuccess) =>
|
||||||
|
defHttp.delete({ url: Api.deleteBatch, params }, { joinParamsToUrl: true }).then(() => handleSuccess());
|
||||||
|
|
||||||
|
export const saveOrUpdate = (params, isUpdate) => {
|
||||||
|
const url = isUpdate ? Api.edit : Api.save;
|
||||||
|
return defHttp.post({ url, params }, { successMessageMode: 'none' });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getExportUrl = Api.exportXls;
|
||||||
|
export const getImportUrl = Api.importExcel;
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||||
|
import { JVxeColumn, JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||||
|
import { list as dictList } from '/@/views/system/dict/dict.api';
|
||||||
|
import { loadTreeData } from '/@/api/common/api';
|
||||||
|
|
||||||
|
export const SOURCE_TYPE_OPTIONS = [
|
||||||
|
{ label: '数据字典', value: 'dict' },
|
||||||
|
{ label: '分类字典', value: 'category' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const sourceTypeTextMap: Record<string, string> = {
|
||||||
|
dict: '数据字典',
|
||||||
|
category: '分类字典',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const columns: BasicColumn[] = [
|
||||||
|
{ title: '种类键值', align: 'center', dataIndex: 'kindKey', width: 120 },
|
||||||
|
{ title: '种类名称', align: 'center', dataIndex: 'kindName', width: 140 },
|
||||||
|
{
|
||||||
|
title: '数据源',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'sourceType',
|
||||||
|
width: 100,
|
||||||
|
customRender: ({ text }) => sourceTypeTextMap[String(text || '')] || text || '',
|
||||||
|
},
|
||||||
|
{ title: '根名称', align: 'center', dataIndex: 'sourceRootName', width: 140 },
|
||||||
|
{ title: '对应分类', align: 'center', dataIndex: 'categoryRefName', width: 140 },
|
||||||
|
{ title: '优先级', align: 'center', dataIndex: 'priority', width: 80 },
|
||||||
|
{ title: '租户ID', align: 'center', dataIndex: 'tenantId', width: 80, defaultHidden: true },
|
||||||
|
{ title: '创建时间', align: 'center', dataIndex: 'createTime', width: 165 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const searchFormSchema: FormSchema[] = [
|
||||||
|
{ label: '种类键值', field: 'kindKey', component: 'Input', colProps: { span: 6 } },
|
||||||
|
{ label: '种类名称', field: 'kindName', component: 'Input', colProps: { span: 6 } },
|
||||||
|
{
|
||||||
|
label: '数据源',
|
||||||
|
field: 'sourceType',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: { options: SOURCE_TYPE_OPTIONS, allowClear: true },
|
||||||
|
colProps: { span: 6 },
|
||||||
|
},
|
||||||
|
{ label: '根编码', field: 'sourceRootCode', component: 'Input', colProps: { span: 6 } },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const batchFormSchema: FormSchema[] = [
|
||||||
|
{
|
||||||
|
label: '数据源',
|
||||||
|
field: 'sourceType',
|
||||||
|
component: 'Select',
|
||||||
|
required: true,
|
||||||
|
defaultValue: 'category',
|
||||||
|
componentProps: { options: SOURCE_TYPE_OPTIONS },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数据字典',
|
||||||
|
field: 'dictRootCode',
|
||||||
|
component: 'ApiSelect',
|
||||||
|
required: true,
|
||||||
|
ifShow: ({ values }) => values.sourceType === 'dict',
|
||||||
|
componentProps: {
|
||||||
|
api: () => dictList({ pageNo: 1, pageSize: 500 }),
|
||||||
|
resultField: 'records',
|
||||||
|
labelField: 'dictName',
|
||||||
|
valueField: 'dictCode',
|
||||||
|
showSearch: true,
|
||||||
|
placeholder: '请选择数据字典根',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '分类字典',
|
||||||
|
field: 'categoryRootCode',
|
||||||
|
component: 'ApiSelect',
|
||||||
|
required: true,
|
||||||
|
ifShow: ({ values }) => values.sourceType === 'category',
|
||||||
|
componentProps: {
|
||||||
|
api: loadTreeData,
|
||||||
|
params: { async: false, pcode: '0' },
|
||||||
|
resultField: '',
|
||||||
|
labelField: 'title',
|
||||||
|
valueField: 'code',
|
||||||
|
showSearch: true,
|
||||||
|
placeholder: '请选择分类字典根',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const editFormSchema: FormSchema[] = [
|
||||||
|
{ label: '', field: 'id', component: 'Input', show: false },
|
||||||
|
{ label: '', field: 'sourceType', component: 'Input', show: false },
|
||||||
|
{ label: '', field: 'sourceRootCode', component: 'Input', show: false },
|
||||||
|
{ label: '', field: 'sourceRootName', component: 'Input', show: false },
|
||||||
|
{ label: '', field: 'categoryRefId', component: 'Input', show: false },
|
||||||
|
{ label: '', field: 'categoryRefCode', component: 'Input', show: false },
|
||||||
|
{
|
||||||
|
label: '种类键值',
|
||||||
|
field: 'kindKey',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: { disabled: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '种类名称',
|
||||||
|
field: 'kindName',
|
||||||
|
component: 'Input',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '对应分类',
|
||||||
|
field: 'categoryRefName',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: { disabled: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '优先级',
|
||||||
|
field: 'priority',
|
||||||
|
component: 'InputNumber',
|
||||||
|
required: true,
|
||||||
|
componentProps: { min: 0, precision: 0, style: { width: '100%' } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '租户ID',
|
||||||
|
field: 'tenantId',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: { disabled: true, style: { width: '100%' } },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const batchJVxeColumns: JVxeColumn[] = [
|
||||||
|
{ title: '', key: 'categoryRefId', type: JVxeTypes.hidden },
|
||||||
|
{ title: '', key: 'categoryRefCode', type: JVxeTypes.hidden },
|
||||||
|
{ title: '', key: 'sourceType', type: JVxeTypes.hidden },
|
||||||
|
{ title: '', key: 'sourceRootCode', type: JVxeTypes.hidden },
|
||||||
|
{ title: '', key: 'sourceRootName', type: JVxeTypes.hidden },
|
||||||
|
{ title: '', key: 'tenantId', type: JVxeTypes.hidden },
|
||||||
|
{ title: '种类键值', key: 'kindKey', type: JVxeTypes.normal, width: 200, minWidth: 160, disabled: true },
|
||||||
|
{ title: '种类名称', key: 'kindName', type: JVxeTypes.input, width: 180, minWidth: 140 },
|
||||||
|
{ title: '对应分类', key: 'categoryRefName', type: JVxeTypes.normal, width: 180, minWidth: 140, disabled: true },
|
||||||
|
{
|
||||||
|
title: '优先级',
|
||||||
|
key: 'priority',
|
||||||
|
type: JVxeTypes.inputNumber,
|
||||||
|
width: 110,
|
||||||
|
minWidth: 90,
|
||||||
|
align: 'center',
|
||||||
|
validateRules: [{ required: true, message: '请输入优先级' }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const superQuerySchema = {
|
||||||
|
kindKey: { title: '种类键值', order: 0, view: 'text' },
|
||||||
|
kindName: { title: '种类名称', order: 1, view: 'text' },
|
||||||
|
sourceType: { title: '数据源', order: 2, view: 'list', enum: SOURCE_TYPE_OPTIONS },
|
||||||
|
sourceRootCode: { title: '根编码', order: 3, view: 'text' },
|
||||||
|
categoryRefName: { title: '对应分类', order: 4, view: 'text' },
|
||||||
|
priority: { title: '优先级', order: 5, view: 'number' },
|
||||||
|
};
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||||
|
<template #tableTitle>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
v-auth="'xslmes:mes_xsl_mixer_material_kind_cfg:add'"
|
||||||
|
@click="handleBatchAdd"
|
||||||
|
preIcon="ant-design:plus-outlined"
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
v-auth="'xslmes:mes_xsl_mixer_material_kind_cfg:exportXls'"
|
||||||
|
preIcon="ant-design:export-outlined"
|
||||||
|
@click="onExportXls"
|
||||||
|
>
|
||||||
|
导出
|
||||||
|
</a-button>
|
||||||
|
<j-upload-button
|
||||||
|
type="primary"
|
||||||
|
v-auth="'xslmes:mes_xsl_mixer_material_kind_cfg:importExcel'"
|
||||||
|
preIcon="ant-design:import-outlined"
|
||||||
|
@click="onImportXls"
|
||||||
|
>
|
||||||
|
导入
|
||||||
|
</j-upload-button>
|
||||||
|
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||||
|
<template #overlay>
|
||||||
|
<a-menu>
|
||||||
|
<a-menu-item key="1" @click="batchHandleDelete">
|
||||||
|
<Icon icon="ant-design:delete-outlined" />
|
||||||
|
删除
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</template>
|
||||||
|
<a-button v-auth="'xslmes:mes_xsl_mixer_material_kind_cfg:deleteBatch'">
|
||||||
|
批量操作
|
||||||
|
<Icon icon="mdi:chevron-down" />
|
||||||
|
</a-button>
|
||||||
|
</a-dropdown>
|
||||||
|
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
|
||||||
|
</template>
|
||||||
|
<template #action="{ record }">
|
||||||
|
<TableAction
|
||||||
|
:actions="[
|
||||||
|
{
|
||||||
|
label: '编辑',
|
||||||
|
onClick: handleEdit.bind(null, record),
|
||||||
|
auth: 'xslmes:mes_xsl_mixer_material_kind_cfg:edit',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:dropDownActions="getDropDownAction(record)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</BasicTable>
|
||||||
|
<MesXslMixerMaterialKindCfgBatchModal @register="registerBatchModal" @success="handleSuccess" />
|
||||||
|
<MesXslMixerMaterialKindCfgEditModal @register="registerEditModal" @success="handleSuccess" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" name="xslmes-mesXslMixerMaterialKindCfg" setup>
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
import { BasicTable, TableAction } from '/@/components/Table';
|
||||||
|
import { useModal } from '/@/components/Modal';
|
||||||
|
import { useListPage } from '/@/hooks/system/useListPage';
|
||||||
|
import Icon from '/@/components/Icon';
|
||||||
|
import MesXslMixerMaterialKindCfgBatchModal from './components/MesXslMixerMaterialKindCfgBatchModal.vue';
|
||||||
|
import MesXslMixerMaterialKindCfgEditModal from './components/MesXslMixerMaterialKindCfgEditModal.vue';
|
||||||
|
import { columns, searchFormSchema, superQuerySchema } from './MesXslMixerMaterialKindCfg.data';
|
||||||
|
import { batchDelete, deleteOne, getExportUrl, getImportUrl, list } from './MesXslMixerMaterialKindCfg.api';
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】种类配置变更后清除前端 lookup 缓存-----------
|
||||||
|
import { clearMixingMaterialKindLookupCache } from '../mesXslMixingSpec/MesXslMixingSpec.data';
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】种类配置变更后清除前端 lookup 缓存-----------
|
||||||
|
|
||||||
|
const queryParam = reactive<any>({});
|
||||||
|
const [registerBatchModal, { openModal: openBatchModal }] = useModal();
|
||||||
|
const [registerEditModal, { openModal: openEditModal }] = useModal();
|
||||||
|
|
||||||
|
const { tableContext, onExportXls, onImportXls } = useListPage({
|
||||||
|
tableProps: {
|
||||||
|
title: '密炼物料种类配置',
|
||||||
|
api: list,
|
||||||
|
columns,
|
||||||
|
canResize: true,
|
||||||
|
formConfig: {
|
||||||
|
schemas: searchFormSchema,
|
||||||
|
labelWidth: 100,
|
||||||
|
autoSubmitOnEnter: true,
|
||||||
|
showAdvancedButton: true,
|
||||||
|
},
|
||||||
|
actionColumn: {
|
||||||
|
title: '操作',
|
||||||
|
dataIndex: 'action',
|
||||||
|
width: 160,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { customRender: 'action' },
|
||||||
|
},
|
||||||
|
beforeFetch: (params) => Object.assign(params, queryParam),
|
||||||
|
},
|
||||||
|
exportConfig: {
|
||||||
|
name: '密炼物料种类配置',
|
||||||
|
url: getExportUrl,
|
||||||
|
params: queryParam,
|
||||||
|
},
|
||||||
|
importConfig: {
|
||||||
|
url: getImportUrl,
|
||||||
|
success: handleSuccess,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||||
|
const superQueryConfig = reactive(superQuerySchema);
|
||||||
|
|
||||||
|
function handleSuperQuery(params) {
|
||||||
|
Object.keys(params).forEach((k) => {
|
||||||
|
queryParam[k] = params[k];
|
||||||
|
});
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBatchAdd() {
|
||||||
|
openBatchModal(true, { showFooter: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEdit(record: Recordable) {
|
||||||
|
openEditModal(true, { record, isUpdate: true, showFooter: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDetail(record: Recordable) {
|
||||||
|
openEditModal(true, { record, isUpdate: true, showFooter: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDelete(record) {
|
||||||
|
await deleteOne({ id: record.id }, handleSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function batchHandleDelete() {
|
||||||
|
await batchDelete({ ids: selectedRowKeys.value.join(',') }, handleSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSuccess() {
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】种类配置变更后清除前端 lookup 缓存-----------
|
||||||
|
clearMixingMaterialKindLookupCache();
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】种类配置变更后清除前端 lookup 缓存-----------
|
||||||
|
selectedRowKeys.value = [];
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDropDownAction(record) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '详情',
|
||||||
|
onClick: handleDetail.bind(null, record),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
popConfirm: {
|
||||||
|
title: '是否确认删除',
|
||||||
|
confirm: handleDelete.bind(null, record),
|
||||||
|
placement: 'topLeft',
|
||||||
|
},
|
||||||
|
auth: 'xslmes:mes_xsl_mixer_material_kind_cfg:delete',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
v-bind="$attrs"
|
||||||
|
destroyOnClose
|
||||||
|
title="新增密炼物料种类配置"
|
||||||
|
:width="'92%'"
|
||||||
|
:defaultFullscreen="true"
|
||||||
|
wrapClassName="mes-xsl-mixer-material-kind-batch-modal"
|
||||||
|
@register="registerModal"
|
||||||
|
@ok="handleSubmit"
|
||||||
|
>
|
||||||
|
<div class="batch-modal-body">
|
||||||
|
<BasicForm @register="registerForm">
|
||||||
|
<template #expandAction>
|
||||||
|
<a-button type="primary" :loading="expanding" @click="handleExpand">带出明细</a-button>
|
||||||
|
</template>
|
||||||
|
</BasicForm>
|
||||||
|
<a-divider orientation="left">种类配置明细</a-divider>
|
||||||
|
<div class="batch-table-wrap">
|
||||||
|
<JVxeTable
|
||||||
|
v-if="tableReady"
|
||||||
|
ref="lineTableRef"
|
||||||
|
toolbar
|
||||||
|
row-number
|
||||||
|
rowSelection
|
||||||
|
keep-source
|
||||||
|
:insert-row="false"
|
||||||
|
:max-height="tableMaxHeight"
|
||||||
|
:loading="lineLoading"
|
||||||
|
:columns="batchJVxeColumns"
|
||||||
|
:dataSource="lineDataSource"
|
||||||
|
:toolbar-config="{ btn: ['remove'] }"
|
||||||
|
:add-btn-cfg="{ enabled: false }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue';
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||||
|
import type { JVxeTableInstance } from '/@/components/jeecg/JVxeTable/types';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import { useUserStore } from '/@/store/modules/user';
|
||||||
|
import { batchFormSchema, batchJVxeColumns } from '../MesXslMixerMaterialKindCfg.data';
|
||||||
|
import { addBatch, expandLines } from '../MesXslMixerMaterialKindCfg.api';
|
||||||
|
|
||||||
|
const emit = defineEmits(['register', 'success']);
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const tableReady = ref(false);
|
||||||
|
const lineLoading = ref(false);
|
||||||
|
const expanding = ref(false);
|
||||||
|
const lineDataSource = ref<Recordable[]>([]);
|
||||||
|
const lineTableRef = ref<JVxeTableInstance>();
|
||||||
|
const tableMaxHeight = ref(560);
|
||||||
|
|
||||||
|
function refreshTableHeight() {
|
||||||
|
// 预留顶部表单、标题与底部按钮区域,表格尽量占满可视区
|
||||||
|
tableMaxHeight.value = Math.max(420, window.innerHeight - 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [registerForm, { resetFields, validate, getFieldsValue }] = useForm({
|
||||||
|
labelWidth: 110,
|
||||||
|
schemas: [
|
||||||
|
...batchFormSchema,
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
field: 'expandAction',
|
||||||
|
component: 'Input',
|
||||||
|
slot: 'expandAction',
|
||||||
|
colProps: { span: 24 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
showActionButtonGroup: false,
|
||||||
|
baseColProps: { span: 12 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => {
|
||||||
|
tableReady.value = false;
|
||||||
|
lineDataSource.value = [];
|
||||||
|
refreshTableHeight();
|
||||||
|
await resetFields();
|
||||||
|
setModalProps({ confirmLoading: false, showCancelBtn: true, showOkBtn: true });
|
||||||
|
tableReady.value = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
refreshTableHeight();
|
||||||
|
window.addEventListener('resize', refreshTableHeight);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('resize', refreshTableHeight);
|
||||||
|
});
|
||||||
|
|
||||||
|
function resolveTenantId() {
|
||||||
|
const tenant = userStore.getTenant;
|
||||||
|
if (tenant == null || tenant === '') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const num = Number(tenant);
|
||||||
|
return Number.isNaN(num) ? undefined : num;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveSourceRootCode(values: Recordable) {
|
||||||
|
if (values.sourceType === 'dict') {
|
||||||
|
return values.dictRootCode;
|
||||||
|
}
|
||||||
|
return values.categoryRootCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleExpand() {
|
||||||
|
try {
|
||||||
|
const values = await validate();
|
||||||
|
const sourceRootCode = resolveSourceRootCode(values);
|
||||||
|
if (!sourceRootCode) {
|
||||||
|
createMessage.warning(values.sourceType === 'dict' ? '请选择数据字典根' : '请选择分类字典根');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expanding.value = true;
|
||||||
|
const tenantId = resolveTenantId();
|
||||||
|
const raw = await expandLines({
|
||||||
|
sourceType: values.sourceType,
|
||||||
|
sourceRootCode,
|
||||||
|
tenantId,
|
||||||
|
});
|
||||||
|
const rows = Array.isArray(raw) ? raw : (raw as Recordable)?.result ?? [];
|
||||||
|
if (!rows.length) {
|
||||||
|
createMessage.warning('未带出任何明细,可能均已配置');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const mergedTenant = tenantId ?? rows[0]?.tenantId;
|
||||||
|
lineDataSource.value = rows.map((row) => ({
|
||||||
|
...row,
|
||||||
|
tenantId: mergedTenant,
|
||||||
|
}));
|
||||||
|
createMessage.success(`已带出 ${rows.length} 条明细`);
|
||||||
|
} catch (e: any) {
|
||||||
|
createMessage.error(e?.message || '带出明细失败');
|
||||||
|
} finally {
|
||||||
|
expanding.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
const lineRef = lineTableRef.value as any;
|
||||||
|
const tableData = (lineRef?.getTableData?.() || lineDataSource.value || []) as Recordable[];
|
||||||
|
if (!tableData.length) {
|
||||||
|
createMessage.warning('请先选择根字典/分类并带出明细');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const errMap = await lineRef?.validateTable?.();
|
||||||
|
if (errMap) {
|
||||||
|
createMessage.warning('请完善明细中的种类名称与优先级');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tenantId = resolveTenantId();
|
||||||
|
const payload = tableData.map((row) => ({
|
||||||
|
...row,
|
||||||
|
tenantId: row.tenantId ?? tenantId,
|
||||||
|
}));
|
||||||
|
try {
|
||||||
|
setModalProps({ confirmLoading: true });
|
||||||
|
await addBatch(payload);
|
||||||
|
createMessage.success('新增成功');
|
||||||
|
closeModal();
|
||||||
|
emit('success');
|
||||||
|
} finally {
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.batch-modal-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: calc(100vh - 200px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-table-wrap {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 420px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal v-bind="$attrs" destroyOnClose :title="title" width="640px" @register="registerModal" @ok="handleSubmit">
|
||||||
|
<BasicForm @register="registerForm" />
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, unref } from 'vue';
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import { editFormSchema } from '../MesXslMixerMaterialKindCfg.data';
|
||||||
|
import { saveOrUpdate } from '../MesXslMixerMaterialKindCfg.api';
|
||||||
|
|
||||||
|
const emit = defineEmits(['register', 'success']);
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
const isUpdate = ref(true);
|
||||||
|
const isDetail = ref(false);
|
||||||
|
|
||||||
|
const [registerForm, { resetFields, setFieldsValue, validate, setProps }] = useForm({
|
||||||
|
labelWidth: 110,
|
||||||
|
schemas: editFormSchema,
|
||||||
|
showActionButtonGroup: false,
|
||||||
|
baseColProps: { span: 24 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
|
await resetFields();
|
||||||
|
setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
|
||||||
|
isUpdate.value = !!data?.isUpdate;
|
||||||
|
isDetail.value = !data?.showFooter;
|
||||||
|
if (data?.record) {
|
||||||
|
await setFieldsValue({ ...data.record });
|
||||||
|
}
|
||||||
|
setProps({ disabled: !data?.showFooter });
|
||||||
|
});
|
||||||
|
|
||||||
|
const title = computed(() => (!unref(isUpdate) ? '新增' : unref(isDetail) ? '详情' : '编辑'));
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
try {
|
||||||
|
const values = await validate();
|
||||||
|
setModalProps({ confirmLoading: true });
|
||||||
|
await saveOrUpdate(values, true);
|
||||||
|
createMessage.success('编辑成功');
|
||||||
|
closeModal();
|
||||||
|
emit('success');
|
||||||
|
} finally {
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
import { Modal } from 'ant-design-vue';
|
||||||
|
|
||||||
|
enum Api {
|
||||||
|
list = '/xslmes/mesXslMixingSpec/list',
|
||||||
|
save = '/xslmes/mesXslMixingSpec/add',
|
||||||
|
edit = '/xslmes/mesXslMixingSpec/edit',
|
||||||
|
deleteOne = '/xslmes/mesXslMixingSpec/delete',
|
||||||
|
deleteBatch = '/xslmes/mesXslMixingSpec/deleteBatch',
|
||||||
|
importExcel = '/xslmes/mesXslMixingSpec/importExcel',
|
||||||
|
exportXls = '/xslmes/mesXslMixingSpec/exportXls',
|
||||||
|
queryById = '/xslmes/mesXslMixingSpec/queryById',
|
||||||
|
queryIssueNumberOptions = '/xslmes/mesXslMixingSpec/queryIssueNumberOptions',
|
||||||
|
queryPurposeOptions = '/xslmes/mesXslMixingSpec/queryPurposeOptions',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getExportUrl = Api.exportXls;
|
||||||
|
export const getImportUrl = Api.importExcel;
|
||||||
|
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||||
|
export const queryById = (params) => defHttp.get({ url: Api.queryById, params });
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方主子表保存延长超时避免误报失败-----------
|
||||||
|
export const saveOrUpdate = (params, isUpdate) =>
|
||||||
|
defHttp.post({ url: isUpdate ? Api.edit : Api.save, params, timeout: 60 * 1000 });
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A45】混炼示方主子表保存延长超时避免误报失败-----------
|
||||||
|
export const queryIssueNumberOptions = (params) => defHttp.get({ url: Api.queryIssueNumberOptions, params });
|
||||||
|
export const queryPurposeOptions = (params) => defHttp.get({ url: Api.queryPurposeOptions, params });
|
||||||
|
|
||||||
|
export const deleteOne = (params, handleSuccess) =>
|
||||||
|
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => handleSuccess());
|
||||||
|
|
||||||
|
export const batchDelete = (params, handleSuccess) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: '确认删除',
|
||||||
|
content: '是否删除选中数据',
|
||||||
|
okText: '确认',
|
||||||
|
cancelText: '取消',
|
||||||
|
onOk: () =>
|
||||||
|
defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => handleSuccess()),
|
||||||
|
});
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||||
|
<template #tableTitle>
|
||||||
|
<a-button type="primary" v-auth="'xslmes:mes_xsl_mixing_spec:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增 </a-button>
|
||||||
|
<a-button type="primary" v-auth="'xslmes:mes_xsl_mixing_spec:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出 </a-button>
|
||||||
|
<j-upload-button type="primary" v-auth="'xslmes:mes_xsl_mixing_spec:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">
|
||||||
|
导入
|
||||||
|
</j-upload-button>
|
||||||
|
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||||
|
<template #overlay>
|
||||||
|
<a-menu>
|
||||||
|
<a-menu-item key="1" @click="batchHandleDelete">
|
||||||
|
<Icon icon="ant-design:delete-outlined" />
|
||||||
|
删除
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</template>
|
||||||
|
<a-button v-auth="'xslmes:mes_xsl_mixing_spec:deleteBatch'">
|
||||||
|
批量操作
|
||||||
|
<Icon icon="mdi:chevron-down" />
|
||||||
|
</a-button>
|
||||||
|
</a-dropdown>
|
||||||
|
</template>
|
||||||
|
<template #action="{ record }">
|
||||||
|
<TableAction :actions="getTableActions(record)" />
|
||||||
|
</template>
|
||||||
|
</BasicTable>
|
||||||
|
<MesXslMixingSpecModal @register="registerModal" @success="handleSuccess" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" name="xslmes-mesXslMixingSpec" setup>
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
import { BasicTable, TableAction } from '/@/components/Table';
|
||||||
|
import { useModal } from '/@/components/Modal';
|
||||||
|
import { useListPage } from '/@/hooks/system/useListPage';
|
||||||
|
import Icon from '/@/components/Icon';
|
||||||
|
import MesXslMixingSpecModal from './components/MesXslMixingSpecModal.vue';
|
||||||
|
import { columns, searchFormSchema } from './MesXslMixingSpec.data';
|
||||||
|
import { list, deleteOne, batchDelete, getExportUrl, getImportUrl } from './MesXslMixingSpec.api';
|
||||||
|
|
||||||
|
const queryParam = reactive<any>({});
|
||||||
|
const [registerModal, { openModal }] = useModal();
|
||||||
|
|
||||||
|
const { tableContext, onExportXls, onImportXls } = useListPage({
|
||||||
|
tableProps: {
|
||||||
|
title: '混炼示方',
|
||||||
|
api: list,
|
||||||
|
columns,
|
||||||
|
canResize: true,
|
||||||
|
formConfig: {
|
||||||
|
schemas: searchFormSchema,
|
||||||
|
labelWidth: 90,
|
||||||
|
autoSubmitOnEnter: true,
|
||||||
|
},
|
||||||
|
actionColumn: {
|
||||||
|
title: '操作',
|
||||||
|
dataIndex: 'action',
|
||||||
|
width: 160,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { customRender: 'action' },
|
||||||
|
},
|
||||||
|
beforeFetch: (params) => Object.assign(params, queryParam),
|
||||||
|
},
|
||||||
|
exportConfig: {
|
||||||
|
name: '混炼示方',
|
||||||
|
url: getExportUrl,
|
||||||
|
params: queryParam,
|
||||||
|
},
|
||||||
|
importConfig: {
|
||||||
|
url: getImportUrl,
|
||||||
|
success: handleSuccess,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||||
|
|
||||||
|
function handleAdd() {
|
||||||
|
openModal(true, { isUpdate: false, showFooter: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEdit(record: Recordable) {
|
||||||
|
openModal(true, { record, isUpdate: true, showFooter: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDetail(record: Recordable) {
|
||||||
|
openModal(true, { record, isUpdate: true, showFooter: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDelete(record: Recordable) {
|
||||||
|
deleteOne({ id: record.id }, handleSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
function batchHandleDelete() {
|
||||||
|
batchDelete({ ids: selectedRowKeys.value.join(',') }, handleSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSuccess() {
|
||||||
|
reload();
|
||||||
|
selectedRowKeys.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTableActions(record: Recordable) {
|
||||||
|
return [
|
||||||
|
{ label: '编辑', onClick: handleEdit.bind(null, record), auth: 'xslmes:mes_xsl_mixing_spec:edit' },
|
||||||
|
{ label: '详情', onClick: handleDetail.bind(null, record) },
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
auth: 'xslmes:mes_xsl_mixing_spec:delete',
|
||||||
|
popConfirm: { title: '是否确认删除', confirm: handleDelete.bind(null, record) },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
<template>
|
||||||
|
<Popover
|
||||||
|
v-model:open="popoverOpen"
|
||||||
|
trigger="click"
|
||||||
|
placement="bottomRight"
|
||||||
|
:getPopupContainer="getPopoverContainer"
|
||||||
|
:overlayClassName="`${prefixCls}__popover`"
|
||||||
|
@open-change="handleOpenChange"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<div :class="`${prefixCls}__title`">
|
||||||
|
<Checkbox :indeterminate="indeterminate" :checked="checkAll" :disabled="loading || !allCategoryIds.length" @change="onCheckAllChange">
|
||||||
|
小类展示
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<Spin :spinning="loading || refreshing">
|
||||||
|
<div v-if="!loading && !groupedCategories.length" :class="`${prefixCls}__empty`">
|
||||||
|
暂无物料小类,请确认分类字典 XSLMES_MATERIAL 已配置
|
||||||
|
</div>
|
||||||
|
<div v-else :class="`${prefixCls}__list`">
|
||||||
|
<div v-for="group in groupedCategories" :key="group.majorId" :class="`${prefixCls}__group`">
|
||||||
|
<div :class="`${prefixCls}__group-title`">{{ group.majorName }}</div>
|
||||||
|
<div :class="`${prefixCls}__group-options`">
|
||||||
|
<Checkbox
|
||||||
|
v-for="opt in group.options"
|
||||||
|
:key="opt.value"
|
||||||
|
:checked="isMinorVisible(opt.value)"
|
||||||
|
@change="(e) => onMinorVisibleChange(opt.value, e.target.checked)"
|
||||||
|
>
|
||||||
|
{{ opt.label }}
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
<div :class="`${prefixCls}__footer`">
|
||||||
|
<a-button size="small" :loading="refreshing" :disabled="loading" @click="handleRefresh">刷新</a-button>
|
||||||
|
<div :class="`${prefixCls}__footer-actions`">
|
||||||
|
<a-button size="small" :disabled="loading || refreshing || !allCategoryIds.length" @click="handleReset">重置</a-button>
|
||||||
|
<a-button size="small" type="primary" :disabled="loading || refreshing || !allCategoryIds.length" @click="handleSave">保存</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<a-button size="small" class="mixing-material-category-setting-btn" :disabled="loading" title="小类展示设置">
|
||||||
|
<Icon icon="ant-design:setting-outlined" />
|
||||||
|
</a-button>
|
||||||
|
</Popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, watch, type PropType } from 'vue';
|
||||||
|
import { Popover, Checkbox, Spin } from 'ant-design-vue';
|
||||||
|
import type { CheckboxChangeEvent } from 'ant-design-vue/lib/checkbox/interface';
|
||||||
|
import { Icon } from '/@/components/Icon';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import { saveMixingMaterialPickerHiddenCategoryIds, type MixingMaterialPickerCategoryItem } from '../MesXslMixingSpec.data';
|
||||||
|
|
||||||
|
const prefixCls = 'mixing-material-category-setting';
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
categories: {
|
||||||
|
type: Array as PropType<MixingMaterialPickerCategoryItem[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
hiddenCategoryIds: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
refreshing: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:hiddenCategoryIds', 'change', 'refresh']);
|
||||||
|
|
||||||
|
const popoverOpen = ref(false);
|
||||||
|
const draftVisibleIds = ref<string[]>([]);
|
||||||
|
|
||||||
|
function getPopoverContainer() {
|
||||||
|
return document.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allCategoryIds = computed(() => (props.categories || []).map((item) => item.id));
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类设置按大类分组展示-----------
|
||||||
|
const groupedCategories = computed(() => {
|
||||||
|
const groupMap = new Map<string, { majorId: string; majorName: string; options: { label: string; value: string }[] }>();
|
||||||
|
(props.categories || []).forEach((item) => {
|
||||||
|
const majorId = item.majorId || 'unknown';
|
||||||
|
const majorName = item.majorName || '其他';
|
||||||
|
const group = groupMap.get(majorId) || { majorId, majorName, options: [] };
|
||||||
|
group.options.push({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
});
|
||||||
|
groupMap.set(majorId, group);
|
||||||
|
});
|
||||||
|
return Array.from(groupMap.values());
|
||||||
|
});
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗小类设置按大类分组展示-----------
|
||||||
|
|
||||||
|
const checkAll = computed(() => {
|
||||||
|
const all = allCategoryIds.value;
|
||||||
|
if (!all.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return draftVisibleIds.value.length === all.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
const indeterminate = computed(() => {
|
||||||
|
const total = allCategoryIds.value.length;
|
||||||
|
const checked = draftVisibleIds.value.length;
|
||||||
|
return checked > 0 && checked < total;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [props.hiddenCategoryIds, props.categories],
|
||||||
|
() => {
|
||||||
|
syncDraftFromHidden();
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
function syncDraftFromHidden() {
|
||||||
|
const hidden = new Set((props.hiddenCategoryIds || []).map(String));
|
||||||
|
draftVisibleIds.value = allCategoryIds.value.filter((id) => !hidden.has(String(id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOpenChange(open: boolean) {
|
||||||
|
popoverOpen.value = open;
|
||||||
|
if (open) {
|
||||||
|
syncDraftFromHidden();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCheckAllChange(e: CheckboxChangeEvent) {
|
||||||
|
draftVisibleIds.value = e.target.checked ? [...allCategoryIds.value] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】小类展示分组勾选互不覆盖-----------
|
||||||
|
function isMinorVisible(id: string) {
|
||||||
|
return draftVisibleIds.value.map(String).includes(String(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMinorVisibleChange(id: string, checked: boolean) {
|
||||||
|
const visibleSet = new Set(draftVisibleIds.value.map(String));
|
||||||
|
const key = String(id);
|
||||||
|
if (checked) {
|
||||||
|
visibleSet.add(key);
|
||||||
|
} else {
|
||||||
|
visibleSet.delete(key);
|
||||||
|
}
|
||||||
|
draftVisibleIds.value = allCategoryIds.value.filter((itemId) => visibleSet.has(String(itemId)));
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】小类展示分组勾选互不覆盖-----------
|
||||||
|
|
||||||
|
function handleReset() {
|
||||||
|
draftVisibleIds.value = [...allCategoryIds.value];
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】小类设置刷新分类字典-----------
|
||||||
|
function handleRefresh() {
|
||||||
|
emit('refresh');
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】小类设置刷新分类字典-----------
|
||||||
|
|
||||||
|
function handleSave() {
|
||||||
|
const visibleSet = new Set(draftVisibleIds.value.map(String));
|
||||||
|
const hidden = allCategoryIds.value.filter((id) => !visibleSet.has(String(id)));
|
||||||
|
saveMixingMaterialPickerHiddenCategoryIds(hidden);
|
||||||
|
emit('update:hiddenCategoryIds', hidden);
|
||||||
|
emit('change', hidden);
|
||||||
|
popoverOpen.value = false;
|
||||||
|
createMessage.success('小类展示设置已保存');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.mixing-material-category-setting-btn {
|
||||||
|
padding-inline: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.mixing-material-category-setting__popover {
|
||||||
|
z-index: 1600 !important;
|
||||||
|
|
||||||
|
.ant-popover-inner-content {
|
||||||
|
width: 320px;
|
||||||
|
max-width: 80vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-category-setting__empty {
|
||||||
|
padding: 12px 0;
|
||||||
|
color: var(--text-color-secondary, rgba(0, 0, 0, 0.45));
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-category-setting__list {
|
||||||
|
max-height: 320px;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 4px 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-category-setting__group + .mixing-material-category-setting__group {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-category-setting__group-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: var(--text-color, rgba(0, 0, 0, 0.88));
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-category-setting__group {
|
||||||
|
.mixing-material-category-setting__group-options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-category-setting__footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid var(--border-color-base, #f0f0f0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-category-setting__footer-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<Popover
|
||||||
|
v-model:open="popoverOpen"
|
||||||
|
trigger="click"
|
||||||
|
placement="bottomRight"
|
||||||
|
:overlayClassName="`${prefixCls}__popover`"
|
||||||
|
@open-change="handleOpenChange"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<div :class="`${prefixCls}__title`">
|
||||||
|
<Checkbox :indeterminate="indeterminate" :checked="checkAll" @change="onCheckAllChange">列展示</Checkbox>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<div :class="`${prefixCls}__list`">
|
||||||
|
<CheckboxGroup v-model:value="draftCheckedList" :options="columnOptions" />
|
||||||
|
</div>
|
||||||
|
<div :class="`${prefixCls}__footer`">
|
||||||
|
<a-button size="small" @click="handleReset">重置</a-button>
|
||||||
|
<a-button size="small" type="primary" @click="handleSave">保存</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<a-tooltip title="列设置">
|
||||||
|
<a-button size="small" class="mixing-material-column-setting-btn" @click.stop>
|
||||||
|
<Icon icon="ant-design:setting-outlined" />
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</Popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, type PropType } from 'vue';
|
||||||
|
import { Popover, Checkbox } from 'ant-design-vue';
|
||||||
|
import type { CheckboxChangeEvent } from 'ant-design-vue/lib/checkbox/interface';
|
||||||
|
import { Icon } from '/@/components/Icon';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import {
|
||||||
|
MIXING_MATERIAL_LOCKED_COLUMN_KEYS,
|
||||||
|
getMixingMaterialColumnSettingItems,
|
||||||
|
saveMixingMaterialHiddenColumnKeys,
|
||||||
|
type MixingMaterialColumnSettingItem,
|
||||||
|
} from '../MesXslMixingSpec.data';
|
||||||
|
|
||||||
|
const CheckboxGroup = Checkbox.Group;
|
||||||
|
const prefixCls = 'mixing-material-column-setting';
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
hiddenKeys: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:hiddenKeys', value: string[]): void;
|
||||||
|
(e: 'change', value: string[]): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const popoverOpen = ref(false);
|
||||||
|
const columnItems = ref<MixingMaterialColumnSettingItem[]>(getMixingMaterialColumnSettingItems());
|
||||||
|
const allKeys = computed(() => columnItems.value.map((item) => item.key));
|
||||||
|
const lockableKeys = computed(() => columnItems.value.filter((item) => !item.locked).map((item) => item.key));
|
||||||
|
const draftCheckedList = ref<string[]>([]);
|
||||||
|
|
||||||
|
const columnOptions = computed(() =>
|
||||||
|
columnItems.value.map((item) => ({
|
||||||
|
label: item.title,
|
||||||
|
value: item.key,
|
||||||
|
disabled: item.locked,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
const checkAll = computed(() => {
|
||||||
|
const keys = lockableKeys.value;
|
||||||
|
return keys.length > 0 && keys.every((key) => draftCheckedList.value.includes(key));
|
||||||
|
});
|
||||||
|
|
||||||
|
const indeterminate = computed(() => {
|
||||||
|
const keys = lockableKeys.value;
|
||||||
|
const checkedCount = keys.filter((key) => draftCheckedList.value.includes(key)).length;
|
||||||
|
return checkedCount > 0 && checkedCount < keys.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
function ensureLockedChecked() {
|
||||||
|
const next = new Set(draftCheckedList.value);
|
||||||
|
MIXING_MATERIAL_LOCKED_COLUMN_KEYS.forEach((key) => next.add(key));
|
||||||
|
draftCheckedList.value = Array.from(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncDraftFromHidden(hiddenKeys: string[]) {
|
||||||
|
const hiddenSet = new Set(hiddenKeys || []);
|
||||||
|
draftCheckedList.value = allKeys.value.filter((key) => !hiddenSet.has(key));
|
||||||
|
ensureLockedChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildHiddenKeysFromDraft() {
|
||||||
|
ensureLockedChecked();
|
||||||
|
return allKeys.value.filter((key) => !draftCheckedList.value.includes(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOpenChange(open: boolean) {
|
||||||
|
if (open) {
|
||||||
|
syncDraftFromHidden(props.hiddenKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCheckAllChange(e: CheckboxChangeEvent) {
|
||||||
|
draftCheckedList.value = e.target.checked ? [...allKeys.value] : [...MIXING_MATERIAL_LOCKED_COLUMN_KEYS];
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReset() {
|
||||||
|
draftCheckedList.value = [...allKeys.value];
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSave() {
|
||||||
|
const hiddenKeys = buildHiddenKeysFromDraft();
|
||||||
|
saveMixingMaterialHiddenColumnKeys(hiddenKeys);
|
||||||
|
emit('update:hiddenKeys', hiddenKeys);
|
||||||
|
emit('change', hiddenKeys);
|
||||||
|
createMessage.success('保存成功');
|
||||||
|
popoverOpen.value = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.mixing-material-column-setting-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding-inline: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.mixing-material-column-setting__popover {
|
||||||
|
.mixing-material-column-setting__title {
|
||||||
|
min-width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-column-setting__list {
|
||||||
|
max-height: 320px;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.ant-checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-checkbox-group-item {
|
||||||
|
margin-inline-start: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-column-setting__footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
padding-top: 4px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,462 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
v-bind="$attrs"
|
||||||
|
title="选择密炼物料"
|
||||||
|
:width="1280"
|
||||||
|
:zIndex="1500"
|
||||||
|
wrapClassName="mixing-material-picker-modal-wrap"
|
||||||
|
@register="registerModal"
|
||||||
|
@ok="handleOk"
|
||||||
|
>
|
||||||
|
<div class="mixing-material-picker">
|
||||||
|
<div class="mixing-material-picker-toolbar">
|
||||||
|
<a-input
|
||||||
|
v-model:value="keyword"
|
||||||
|
allow-clear
|
||||||
|
placeholder="关键字(物料编码/名称/描述)"
|
||||||
|
style="width: 280px"
|
||||||
|
@pressEnter="reloadTable"
|
||||||
|
/>
|
||||||
|
<a-button type="primary" @click="reloadTable">搜索</a-button>
|
||||||
|
<MesXslMixingMaterialCategorySetting
|
||||||
|
v-model:hiddenCategoryIds="hiddenCategoryIds"
|
||||||
|
:categories="allMinorCategories"
|
||||||
|
:loading="treeLoading"
|
||||||
|
:refreshing="categoryRefreshing"
|
||||||
|
@change="handleCategoryVisibilityChange"
|
||||||
|
@refresh="handleRefreshCategoryTree"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mixing-material-picker-body">
|
||||||
|
<aside class="mixing-material-picker-sider">
|
||||||
|
<div class="mixing-material-picker-sider-title">物料小类</div>
|
||||||
|
<Spin :spinning="treeLoading">
|
||||||
|
<BasicTree
|
||||||
|
:treeData="visibleCategoryTree"
|
||||||
|
:selectedKeys="selectedCategoryKeys"
|
||||||
|
:expandedKeys="expandedCategoryKeys"
|
||||||
|
defaultExpandLevel="2"
|
||||||
|
@update:selectedKeys="onCategorySelect"
|
||||||
|
@update:expandedKeys="onExpandedKeysChange"
|
||||||
|
/>
|
||||||
|
</Spin>
|
||||||
|
</aside>
|
||||||
|
<div class="mixing-material-picker-main">
|
||||||
|
<BasicTable @register="registerTable">
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.dataIndex === 'pickerWeighMode'">
|
||||||
|
<div class="mixing-material-picker-weigh-mode" @click.stop>
|
||||||
|
<JDictSelectTag
|
||||||
|
:value="getPickerWeighMode(record.id)"
|
||||||
|
:dictCode="MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT"
|
||||||
|
:getPopupContainer="getSelectPopupContainer"
|
||||||
|
:showChooseOption="false"
|
||||||
|
placeholder="请选择"
|
||||||
|
popupClassName="mixing-material-picker-weigh-mode-dropdown"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="(val) => setPickerWeighMode(record.id, val)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.dataIndex === 'pickerMaterialKind'">
|
||||||
|
{{ resolvePickerMaterialKind(record) }}
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</BasicTable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import { Spin } from 'ant-design-vue';
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { BasicTable, useTable } from '/@/components/Table';
|
||||||
|
import { BasicTree } from '/@/components/Tree';
|
||||||
|
import { loadMesMaterialCategoryTreeData, hasMesMaterialCategoryTreeCache } from '/@/views/system/category/category.constants';
|
||||||
|
import { list as mixerList, queryById as queryMixerById } from '/@/views/mes/material/MesMixerMaterial.api';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||||||
|
import MesXslMixingMaterialCategorySetting from './MesXslMixingMaterialCategorySetting.vue';
|
||||||
|
import {
|
||||||
|
applyMixingMaterialFromSelection,
|
||||||
|
EMPTY_MIXER_MATERIAL_KIND_LOOKUP,
|
||||||
|
loadMixingMaterialKindLookup,
|
||||||
|
loadMixingMaterialPickerHiddenCategoryIds,
|
||||||
|
MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT,
|
||||||
|
mixingMaterialPickerTableColumns,
|
||||||
|
resolveMixingMaterialKindForPicker,
|
||||||
|
sanitizeMixingMaterialPickerHiddenCategoryIds,
|
||||||
|
saveMixingMaterialPickerHiddenCategoryIds,
|
||||||
|
type MixingMaterialPickerCategoryItem,
|
||||||
|
type MixerMaterialKindLookup,
|
||||||
|
} from '../MesXslMixingSpec.data';
|
||||||
|
import type { KeyType } from '/@/components/Tree/src/types/tree';
|
||||||
|
|
||||||
|
const TREE_ALL = 'ALL';
|
||||||
|
const emit = defineEmits(['register', 'select']);
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
|
const keyword = ref('');
|
||||||
|
const treeLoading = ref(false);
|
||||||
|
const rawCategoryTree = ref<Recordable[]>([]);
|
||||||
|
const allMajorCategories = ref<Array<{ id: string; name: string; minors: MixingMaterialPickerCategoryItem[] }>>([]);
|
||||||
|
const allMinorCategories = ref<MixingMaterialPickerCategoryItem[]>([]);
|
||||||
|
const hiddenCategoryIds = ref<string[]>(loadMixingMaterialPickerHiddenCategoryIds());
|
||||||
|
const selectedCategoryKeys = ref<KeyType[]>([TREE_ALL]);
|
||||||
|
const expandedCategoryKeys = ref<KeyType[]>([TREE_ALL]);
|
||||||
|
const selectedRow = ref<Recordable | null>(null);
|
||||||
|
const kindLookup = ref<MixerMaterialKindLookup>(EMPTY_MIXER_MATERIAL_KIND_LOOKUP);
|
||||||
|
const pickerWeighModeMap = ref<Record<string, string>>({});
|
||||||
|
const pickerInitializing = ref(false);
|
||||||
|
const categoryRefreshing = ref(false);
|
||||||
|
|
||||||
|
const hiddenCategoryIdSet = computed(() => new Set(hiddenCategoryIds.value.map(String)));
|
||||||
|
|
||||||
|
function getSelectPopupContainer() {
|
||||||
|
return document.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterHiddenCategoryTree(nodes: Recordable[], hidden: Set<string>): Recordable[] {
|
||||||
|
return (nodes || [])
|
||||||
|
.map((major) => {
|
||||||
|
const children = (major.children || [])
|
||||||
|
.filter((minor) => !hidden.has(String(minor.key)))
|
||||||
|
.map((minor) => ({
|
||||||
|
key: minor.key,
|
||||||
|
title: minor.title,
|
||||||
|
}));
|
||||||
|
if (!children.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
key: major.key,
|
||||||
|
title: major.title,
|
||||||
|
children,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean) as Recordable[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const visibleCategoryTree = computed(() => [
|
||||||
|
{
|
||||||
|
key: TREE_ALL,
|
||||||
|
title: '全部小类',
|
||||||
|
children: filterHiddenCategoryTree(rawCategoryTree.value, hiddenCategoryIdSet.value),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
function syncExpandedCategoryKeys() {
|
||||||
|
const keys: KeyType[] = [TREE_ALL];
|
||||||
|
for (const major of visibleCategoryTree.value[0]?.children || []) {
|
||||||
|
keys.push(major.key);
|
||||||
|
}
|
||||||
|
expandedCategoryKeys.value = keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
visibleCategoryTree,
|
||||||
|
() => {
|
||||||
|
syncExpandedCategoryKeys();
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedCategoryFilter = computed(() => {
|
||||||
|
const key = selectedCategoryKeys.value[0];
|
||||||
|
if (!key || key === TREE_ALL) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const keyStr = String(key);
|
||||||
|
const major = allMajorCategories.value.find((item) => item.id === keyStr);
|
||||||
|
if (major) {
|
||||||
|
return { majorCategoryId: major.id };
|
||||||
|
}
|
||||||
|
return { minorCategoryId: keyStr };
|
||||||
|
});
|
||||||
|
|
||||||
|
const [registerTable, { reload, getSelectRowKeys, getSelectRows, clearSelectedRowKeys }] = useTable({
|
||||||
|
api: mixerList,
|
||||||
|
columns: mixingMaterialPickerTableColumns,
|
||||||
|
rowKey: 'id',
|
||||||
|
useSearchForm: false,
|
||||||
|
pagination: { pageSize: 10 },
|
||||||
|
canResize: false,
|
||||||
|
showIndexColumn: true,
|
||||||
|
immediate: false,
|
||||||
|
beforeFetch: (params) => {
|
||||||
|
const next = { ...params, ...selectedCategoryFilter.value };
|
||||||
|
const kw = keyword.value?.trim();
|
||||||
|
if (kw) {
|
||||||
|
next.materialName = `*${kw}*`;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
},
|
||||||
|
rowSelection: {
|
||||||
|
type: 'radio',
|
||||||
|
columnWidth: 48,
|
||||||
|
onChange: (_keys, rows) => {
|
||||||
|
selectedRow.value = rows?.[0] ?? null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
clickToRowSelect: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗打开时初始化(对齐其他SelectModal)-----------
|
||||||
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => {
|
||||||
|
setModalProps({ zIndex: 1500 });
|
||||||
|
await initPickerModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function initPickerModal() {
|
||||||
|
pickerInitializing.value = true;
|
||||||
|
selectedRow.value = null;
|
||||||
|
keyword.value = '';
|
||||||
|
pickerWeighModeMap.value = {};
|
||||||
|
clearSelectedRowKeys?.();
|
||||||
|
hiddenCategoryIds.value = loadMixingMaterialPickerHiddenCategoryIds();
|
||||||
|
selectedCategoryKeys.value = [TREE_ALL];
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】选料弹窗先加载左侧树再查右侧列表-----------
|
||||||
|
try {
|
||||||
|
await loadMaterialCategoryTree();
|
||||||
|
kindLookup.value = await loadMixingMaterialKindLookup(false);
|
||||||
|
reloadTable();
|
||||||
|
} finally {
|
||||||
|
pickerInitializing.value = false;
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】选料弹窗先加载左侧树再查右侧列表-----------
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A50】选料弹窗打开时初始化(对齐其他SelectModal)-----------
|
||||||
|
|
||||||
|
async function loadMaterialCategoryTree(forceReload = false) {
|
||||||
|
const hasCachedTree = !forceReload && (hasMesMaterialCategoryTreeCache() || rawCategoryTree.value.length > 0);
|
||||||
|
if (forceReload || !hasCachedTree) {
|
||||||
|
treeLoading.value = true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const { majors, minors, treeNodes } = await loadMesMaterialCategoryTreeData(forceReload);
|
||||||
|
applyMaterialCategoryTreeData(majors, minors, treeNodes);
|
||||||
|
} catch {
|
||||||
|
rawCategoryTree.value = [];
|
||||||
|
allMajorCategories.value = [];
|
||||||
|
allMinorCategories.value = [];
|
||||||
|
createMessage.warning('加载物料分类树失败,请检查分类根编码 XSLMES_MATERIAL 是否存在。');
|
||||||
|
} finally {
|
||||||
|
treeLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyMaterialCategoryTreeData(
|
||||||
|
majors: Array<{ id: string; name: string; minors: MixingMaterialPickerCategoryItem[] }>,
|
||||||
|
minors: MixingMaterialPickerCategoryItem[],
|
||||||
|
treeNodes: Recordable[],
|
||||||
|
) {
|
||||||
|
rawCategoryTree.value = treeNodes;
|
||||||
|
allMajorCategories.value = majors;
|
||||||
|
allMinorCategories.value = minors;
|
||||||
|
|
||||||
|
const sanitizedHidden = sanitizeMixingMaterialPickerHiddenCategoryIds(
|
||||||
|
minors.map((item) => item.id),
|
||||||
|
hiddenCategoryIds.value,
|
||||||
|
);
|
||||||
|
if (sanitizedHidden.length !== hiddenCategoryIds.value.length) {
|
||||||
|
hiddenCategoryIds.value = sanitizedHidden;
|
||||||
|
saveMixingMaterialPickerHiddenCategoryIds(sanitizedHidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
syncExpandedCategoryKeys();
|
||||||
|
|
||||||
|
if (!minors.length) {
|
||||||
|
createMessage.warning('未加载到物料小类,请确认分类字典根编码 XSLMES_MATERIAL 及其下级分类已配置。');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】小类设置刷新分类字典-----------
|
||||||
|
/** 刷新分类字典:重新拉取小类列表,新增小类默认隐藏,勾选保存后展示到左侧树 */
|
||||||
|
async function handleRefreshCategoryTree() {
|
||||||
|
if (categoryRefreshing.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const previousIds = new Set(allMinorCategories.value.map((item) => String(item.id)));
|
||||||
|
categoryRefreshing.value = true;
|
||||||
|
try {
|
||||||
|
await loadMaterialCategoryTree(true);
|
||||||
|
const newMinorIds = allMinorCategories.value
|
||||||
|
.filter((item) => !previousIds.has(String(item.id)))
|
||||||
|
.map((item) => String(item.id));
|
||||||
|
if (newMinorIds.length) {
|
||||||
|
const nextHidden = sanitizeMixingMaterialPickerHiddenCategoryIds(
|
||||||
|
allMinorCategories.value.map((item) => item.id),
|
||||||
|
[...hiddenCategoryIds.value.map(String), ...newMinorIds],
|
||||||
|
);
|
||||||
|
hiddenCategoryIds.value = nextHidden;
|
||||||
|
createMessage.success(`已刷新,发现 ${newMinorIds.length} 个新小类,请勾选后点击保存`);
|
||||||
|
} else {
|
||||||
|
createMessage.success('已刷新,分类无变化');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
categoryRefreshing.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A52】小类设置刷新分类字典-----------
|
||||||
|
|
||||||
|
function reloadTable() {
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPickerWeighMode(materialId?: string) {
|
||||||
|
if (!materialId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return pickerWeighModeMap.value[String(materialId)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPickerWeighMode(materialId: string | undefined, value?: string) {
|
||||||
|
if (!materialId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const key = String(materialId);
|
||||||
|
const next = { ...pickerWeighModeMap.value };
|
||||||
|
if (value == null || value === '') {
|
||||||
|
delete next[key];
|
||||||
|
} else {
|
||||||
|
next[key] = String(value);
|
||||||
|
}
|
||||||
|
pickerWeighModeMap.value = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCategorySelect(keys: KeyType[]) {
|
||||||
|
selectedCategoryKeys.value = keys?.length ? keys : [TREE_ALL];
|
||||||
|
if (pickerInitializing.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reloadTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onExpandedKeysChange(keys: KeyType[]) {
|
||||||
|
expandedCategoryKeys.value = keys?.length ? keys : [TREE_ALL];
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCategoryVisibilityChange() {
|
||||||
|
const key = selectedCategoryKeys.value[0];
|
||||||
|
if (!key || key === TREE_ALL) {
|
||||||
|
syncExpandedCategoryKeys();
|
||||||
|
reloadTable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const keyStr = String(key);
|
||||||
|
const hidden = hiddenCategoryIdSet.value;
|
||||||
|
const major = allMajorCategories.value.find((item) => item.id === keyStr);
|
||||||
|
if (major) {
|
||||||
|
const hasVisibleMinor = major.minors.some((minor) => !hidden.has(String(minor.id)));
|
||||||
|
if (!hasVisibleMinor) {
|
||||||
|
selectedCategoryKeys.value = [TREE_ALL];
|
||||||
|
}
|
||||||
|
} else if (hidden.has(keyStr)) {
|
||||||
|
selectedCategoryKeys.value = [TREE_ALL];
|
||||||
|
}
|
||||||
|
syncExpandedCategoryKeys();
|
||||||
|
reloadTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePickerMaterialKind(material: Recordable) {
|
||||||
|
const weighMode = getPickerWeighMode(material?.id);
|
||||||
|
const minorId = material?.minorCategoryId ? String(material.minorCategoryId) : '';
|
||||||
|
const minorName = material?.minorCategoryId_dictText || '';
|
||||||
|
return resolveMixingMaterialKindForPicker(kindLookup.value, weighMode, minorId, minorName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveKindForMaterial(material: Recordable, weighMode?: string) {
|
||||||
|
const minorId = material?.minorCategoryId ? String(material.minorCategoryId) : '';
|
||||||
|
const minorName = material?.minorCategoryId_dictText || '';
|
||||||
|
return resolveMixingMaterialKindForPicker(kindLookup.value, weighMode, minorId, minorName);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleOk() {
|
||||||
|
const keys = (getSelectRowKeys?.() || []) as string[];
|
||||||
|
let row = selectedRow.value || ((getSelectRows?.() || []) as Recordable[])[0];
|
||||||
|
if (!row && keys.length) {
|
||||||
|
try {
|
||||||
|
const raw = await queryMixerById({ id: keys[0] });
|
||||||
|
row = (raw as any)?.id != null ? raw : (raw as any)?.result;
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!row?.id) {
|
||||||
|
createMessage.warning('请选择一条密炼物料');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const weighMode = getPickerWeighMode(row.id);
|
||||||
|
const payload: Recordable = { ...row, pickerWeighMode: weighMode };
|
||||||
|
const materialKind = resolveKindForMaterial(row, weighMode);
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】选料未匹配种类时提示检查配置-----------
|
||||||
|
if (!materialKind) {
|
||||||
|
createMessage.warning('未匹配到种类,请检查密炼物料种类配置');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A53】选料未匹配种类时提示检查配置-----------
|
||||||
|
applyMixingMaterialFromSelection(payload, row, materialKind);
|
||||||
|
emit('select', payload);
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.mixing-material-picker {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
min-height: 520px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-picker-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-picker-body {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
min-height: 480px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-picker-sider {
|
||||||
|
width: 240px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 1px solid var(--border-color-base, #f0f0f0);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 8px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-picker-sider-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-picker-main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-material-picker-weigh-mode {
|
||||||
|
min-width: 108px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
/* 嵌套在全屏混炼示方弹窗之上,避免偶发被父弹窗遮挡 */
|
||||||
|
.mixing-material-picker-modal-wrap {
|
||||||
|
z-index: 1500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉挂到 body,避免表格 overflow 裁剪;层级高于 Modal */
|
||||||
|
.mixing-material-picker-weigh-mode-dropdown {
|
||||||
|
z-index: 2100 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,236 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
v-bind="$attrs"
|
||||||
|
title="选取混炼示方"
|
||||||
|
:width="960"
|
||||||
|
:zIndex="1500"
|
||||||
|
:showOkBtn="false"
|
||||||
|
:showCancelBtn="false"
|
||||||
|
wrapClassName="mixing-spec-picker-modal-wrap"
|
||||||
|
@register="registerModal"
|
||||||
|
>
|
||||||
|
<div class="mixing-spec-picker">
|
||||||
|
<div class="mixing-spec-picker-toolbar">
|
||||||
|
<span class="mixing-spec-picker-label">关键字</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="keyword"
|
||||||
|
allow-clear
|
||||||
|
placeholder="规格/用途/发行编号/机台"
|
||||||
|
style="width: 240px"
|
||||||
|
@pressEnter="reloadTable"
|
||||||
|
/>
|
||||||
|
<span class="mixing-spec-picker-label">机台</span>
|
||||||
|
<a-select
|
||||||
|
v-model:value="machineId"
|
||||||
|
allow-clear
|
||||||
|
show-search
|
||||||
|
option-filter-prop="label"
|
||||||
|
placeholder="==请选择=="
|
||||||
|
style="width: 160px"
|
||||||
|
:options="machineOptions"
|
||||||
|
:loading="machineLoading"
|
||||||
|
:getPopupContainer="getSelectPopupContainer"
|
||||||
|
popupClassName="mixing-spec-picker-machine-dropdown"
|
||||||
|
@click.stop
|
||||||
|
/>
|
||||||
|
<a-button type="primary" @click="reloadTable">搜索</a-button>
|
||||||
|
</div>
|
||||||
|
<BasicTable @register="registerTable" />
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<a-button @click="handleClose">关闭</a-button>
|
||||||
|
<a-button type="primary" :loading="confirmLoading" @click="handleConfirm">确认</a-button>
|
||||||
|
<a-button type="primary" :loading="referenceLoading" @click="handleReferenceAdd">参照选中示方新增</a-button>
|
||||||
|
</template>
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { BasicTable, useTable } from '/@/components/Table';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import { list as mixingSpecList, queryById as queryMixingSpecById } from '../MesXslMixingSpec.api';
|
||||||
|
import { mixingSpecHistorySelectColumns } from '../MesXslMixingSpec.data';
|
||||||
|
import { list as equipmentList } from '/@/views/xslmes/mesXslEquipmentLedger/MesXslEquipmentLedger.api';
|
||||||
|
|
||||||
|
const emit = defineEmits(['register', 'edit', 'referenceAdd']);
|
||||||
|
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
|
const keyword = ref('');
|
||||||
|
const machineId = ref<string | undefined>(undefined);
|
||||||
|
const machineOptions = ref<Array<{ label: string; value: string }>>([]);
|
||||||
|
const machineLoading = ref(false);
|
||||||
|
const confirmLoading = ref(false);
|
||||||
|
const referenceLoading = ref(false);
|
||||||
|
const selectedRow = ref<Recordable | null>(null);
|
||||||
|
|
||||||
|
function getSelectPopupContainer() {
|
||||||
|
return document.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [registerTable, { reload, getSelectRowKeys, getSelectRows, setSelectedRowKeys, clearSelectedRowKeys }] = useTable({
|
||||||
|
api: mixingSpecList,
|
||||||
|
columns: mixingSpecHistorySelectColumns,
|
||||||
|
rowKey: 'id',
|
||||||
|
useSearchForm: false,
|
||||||
|
pagination: { pageSize: 30 },
|
||||||
|
canResize: false,
|
||||||
|
showIndexColumn: true,
|
||||||
|
immediate: false,
|
||||||
|
beforeFetch: (params) => ({
|
||||||
|
...params,
|
||||||
|
keyword: keyword.value?.trim() || undefined,
|
||||||
|
machineId: machineId.value || undefined,
|
||||||
|
}),
|
||||||
|
rowSelection: {
|
||||||
|
type: 'radio',
|
||||||
|
columnWidth: 48,
|
||||||
|
onChange: (_keys, rows) => {
|
||||||
|
selectedRow.value = rows?.[0] ?? null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
clickToRowSelect: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
async function loadMachineOptions() {
|
||||||
|
machineLoading.value = true;
|
||||||
|
try {
|
||||||
|
const optionMap = new Map<string, { label: string; value: string }>();
|
||||||
|
const raw = await mixingSpecList({ pageNo: 1, pageSize: 500 });
|
||||||
|
const page = (raw as Recordable)?.records != null ? raw : (raw as Recordable)?.result;
|
||||||
|
const specRecords = ((page?.records || page || []) as Recordable[]).filter(Boolean);
|
||||||
|
specRecords.forEach((row) => {
|
||||||
|
if (!row?.machineId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = String(row.machineId);
|
||||||
|
optionMap.set(value, {
|
||||||
|
value,
|
||||||
|
label: row.machineName || value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!optionMap.size) {
|
||||||
|
const eqRaw = await equipmentList({ pageNo: 1, pageSize: 500 });
|
||||||
|
const eqPage = (eqRaw as Recordable)?.records != null ? eqRaw : (eqRaw as Recordable)?.result;
|
||||||
|
const eqRecords = ((eqPage?.records || eqPage || []) as Recordable[]).filter(Boolean);
|
||||||
|
eqRecords.forEach((row) => {
|
||||||
|
if (!row?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = String(row.id);
|
||||||
|
optionMap.set(value, {
|
||||||
|
value,
|
||||||
|
label: row.equipmentName || row.equipmentCode || value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
machineOptions.value = Array.from(optionMap.values()).sort((a, b) =>
|
||||||
|
a.label.localeCompare(b.label, 'zh-CN'),
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
machineOptions.value = [];
|
||||||
|
} finally {
|
||||||
|
machineLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadTable() {
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveSelectedRow(): Promise<Recordable | null> {
|
||||||
|
const keys = (getSelectRowKeys?.() || []) as string[];
|
||||||
|
let row = selectedRow.value || ((getSelectRows?.() || []) as Recordable[])[0];
|
||||||
|
if (!row?.id && keys.length) {
|
||||||
|
try {
|
||||||
|
const raw = await queryMixingSpecById({ id: keys[0] });
|
||||||
|
row = (raw as Recordable)?.specName != null ? raw : (raw as Recordable)?.result;
|
||||||
|
} catch {
|
||||||
|
row = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return row?.id ? row : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClose() {
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleConfirm() {
|
||||||
|
const row = await resolveSelectedRow();
|
||||||
|
if (!row) {
|
||||||
|
createMessage.warning('请选择一条混炼示方');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
confirmLoading.value = true;
|
||||||
|
try {
|
||||||
|
emit('edit', {
|
||||||
|
mixingSpecId: row.id,
|
||||||
|
specName: row.specName || '',
|
||||||
|
});
|
||||||
|
closeModal();
|
||||||
|
} finally {
|
||||||
|
confirmLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleReferenceAdd() {
|
||||||
|
const row = await resolveSelectedRow();
|
||||||
|
if (!row) {
|
||||||
|
createMessage.warning('请选择一条混炼示方');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
referenceLoading.value = true;
|
||||||
|
try {
|
||||||
|
emit('referenceAdd', {
|
||||||
|
mixingSpecId: row.id,
|
||||||
|
specName: row.specName || '',
|
||||||
|
});
|
||||||
|
closeModal();
|
||||||
|
} finally {
|
||||||
|
referenceLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
|
keyword.value = '';
|
||||||
|
machineId.value = data?.machineId || undefined;
|
||||||
|
selectedRow.value = null;
|
||||||
|
confirmLoading.value = false;
|
||||||
|
referenceLoading.value = false;
|
||||||
|
clearSelectedRowKeys?.();
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
await loadMachineOptions();
|
||||||
|
reload();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.mixing-spec-picker-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-spec-picker-label {
|
||||||
|
color: #333;
|
||||||
|
font-size: 13px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.mixing-spec-picker-modal-wrap {
|
||||||
|
.ant-modal {
|
||||||
|
top: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-spec-picker-machine-dropdown {
|
||||||
|
z-index: 2100 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
v-bind="$attrs"
|
||||||
|
title="选取混合示方(双击表格可选择)"
|
||||||
|
:width="960"
|
||||||
|
:zIndex="1500"
|
||||||
|
wrapClassName="mixing-step-history-picker-modal-wrap"
|
||||||
|
@register="registerModal"
|
||||||
|
@ok="handleOk"
|
||||||
|
>
|
||||||
|
<div class="mixing-step-history-picker">
|
||||||
|
<div class="mixing-step-history-picker-toolbar">
|
||||||
|
<span class="mixing-step-history-picker-label">关键字</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="keyword"
|
||||||
|
allow-clear
|
||||||
|
placeholder="规格/用途/发行编号/机台"
|
||||||
|
style="width: 240px"
|
||||||
|
@pressEnter="reloadTable"
|
||||||
|
/>
|
||||||
|
<span class="mixing-step-history-picker-label">机台</span>
|
||||||
|
<a-select
|
||||||
|
v-model:value="machineId"
|
||||||
|
allow-clear
|
||||||
|
show-search
|
||||||
|
option-filter-prop="label"
|
||||||
|
placeholder="==请选择=="
|
||||||
|
style="width: 160px"
|
||||||
|
:options="machineOptions"
|
||||||
|
:loading="machineLoading"
|
||||||
|
:getPopupContainer="getSelectPopupContainer"
|
||||||
|
popupClassName="mixing-step-history-picker-machine-dropdown"
|
||||||
|
@click.stop
|
||||||
|
/>
|
||||||
|
<a-button type="primary" @click="reloadTable">搜索</a-button>
|
||||||
|
</div>
|
||||||
|
<BasicTable @register="registerTable" @row-dbClick="handleRowDbClick" />
|
||||||
|
</div>
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { BasicTable, useTable } from '/@/components/Table';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import { list as mixingSpecList, queryById as queryMixingSpecById } from '../MesXslMixingSpec.api';
|
||||||
|
import { mixingSpecHistorySelectColumns } from '../MesXslMixingSpec.data';
|
||||||
|
import { list as equipmentList } from '/@/views/xslmes/mesXslEquipmentLedger/MesXslEquipmentLedger.api';
|
||||||
|
|
||||||
|
const emit = defineEmits(['register', 'select']);
|
||||||
|
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
|
const keyword = ref('');
|
||||||
|
const machineId = ref<string | undefined>(undefined);
|
||||||
|
const machineOptions = ref<Array<{ label: string; value: string }>>([]);
|
||||||
|
const machineLoading = ref(false);
|
||||||
|
const excludeSpecId = ref('');
|
||||||
|
const selectedRow = ref<Recordable | null>(null);
|
||||||
|
|
||||||
|
function getSelectPopupContainer() {
|
||||||
|
return document.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [registerTable, { reload, getSelectRowKeys, getSelectRows, setSelectedRowKeys, clearSelectedRowKeys }] = useTable({
|
||||||
|
api: mixingSpecList,
|
||||||
|
columns: mixingSpecHistorySelectColumns,
|
||||||
|
rowKey: 'id',
|
||||||
|
useSearchForm: false,
|
||||||
|
pagination: { pageSize: 30 },
|
||||||
|
canResize: false,
|
||||||
|
showIndexColumn: true,
|
||||||
|
immediate: false,
|
||||||
|
beforeFetch: (params) => ({
|
||||||
|
...params,
|
||||||
|
keyword: keyword.value?.trim() || undefined,
|
||||||
|
machineId: machineId.value || undefined,
|
||||||
|
}),
|
||||||
|
afterFetch: (rows) => {
|
||||||
|
if (!excludeSpecId.value) {
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
return (rows || []).filter((row) => row?.id !== excludeSpecId.value);
|
||||||
|
},
|
||||||
|
rowSelection: {
|
||||||
|
type: 'radio',
|
||||||
|
columnWidth: 48,
|
||||||
|
onChange: (_keys, rows) => {
|
||||||
|
selectedRow.value = rows?.[0] ?? null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
clickToRowSelect: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
async function loadMachineOptions() {
|
||||||
|
machineLoading.value = true;
|
||||||
|
try {
|
||||||
|
const optionMap = new Map<string, { label: string; value: string }>();
|
||||||
|
const raw = await mixingSpecList({ pageNo: 1, pageSize: 500 });
|
||||||
|
const page = (raw as Recordable)?.records != null ? raw : (raw as Recordable)?.result;
|
||||||
|
const specRecords = ((page?.records || page || []) as Recordable[]).filter(Boolean);
|
||||||
|
specRecords.forEach((row) => {
|
||||||
|
if (!row?.machineId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = String(row.machineId);
|
||||||
|
optionMap.set(value, {
|
||||||
|
value,
|
||||||
|
label: row.machineName || value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!optionMap.size) {
|
||||||
|
const eqRaw = await equipmentList({ pageNo: 1, pageSize: 500 });
|
||||||
|
const eqPage = (eqRaw as Recordable)?.records != null ? eqRaw : (eqRaw as Recordable)?.result;
|
||||||
|
const eqRecords = ((eqPage?.records || eqPage || []) as Recordable[]).filter(Boolean);
|
||||||
|
eqRecords.forEach((row) => {
|
||||||
|
if (!row?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const value = String(row.id);
|
||||||
|
optionMap.set(value, {
|
||||||
|
value,
|
||||||
|
label: row.equipmentName || row.equipmentCode || value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
machineOptions.value = Array.from(optionMap.values()).sort((a, b) =>
|
||||||
|
a.label.localeCompare(b.label, 'zh-CN'),
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
machineOptions.value = [];
|
||||||
|
} finally {
|
||||||
|
machineLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadTable() {
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveSelectedRow(): Promise<Recordable | null> {
|
||||||
|
const keys = (getSelectRowKeys?.() || []) as string[];
|
||||||
|
let row = selectedRow.value || ((getSelectRows?.() || []) as Recordable[])[0];
|
||||||
|
if (!row?.id && keys.length) {
|
||||||
|
try {
|
||||||
|
const raw = await queryMixingSpecById({ id: keys[0] });
|
||||||
|
row = (raw as Recordable)?.specName != null ? raw : (raw as Recordable)?.result;
|
||||||
|
} catch {
|
||||||
|
row = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return row?.id ? row : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function confirmSelect(row: Recordable) {
|
||||||
|
if (!row?.id) {
|
||||||
|
createMessage.warning('请选择一条混炼示方');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (row.id === excludeSpecId.value) {
|
||||||
|
createMessage.warning('不能参照当前正在编辑的混炼示方');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit('select', {
|
||||||
|
mixingSpecId: row.id,
|
||||||
|
specName: row.specName || '',
|
||||||
|
machineName: row.machineName || '',
|
||||||
|
issueNumber: row.issueNumber || '',
|
||||||
|
});
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleOk() {
|
||||||
|
const row = await resolveSelectedRow();
|
||||||
|
if (!row) {
|
||||||
|
createMessage.warning('请选择一条混炼示方');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await confirmSelect(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleRowDbClick(record: Recordable) {
|
||||||
|
if (!record?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSelectedRowKeys?.([record.id]);
|
||||||
|
selectedRow.value = record;
|
||||||
|
await confirmSelect(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
|
keyword.value = '';
|
||||||
|
machineId.value = data?.machineId || undefined;
|
||||||
|
excludeSpecId.value = data?.excludeSpecId || '';
|
||||||
|
selectedRow.value = null;
|
||||||
|
clearSelectedRowKeys?.();
|
||||||
|
setModalProps({ confirmLoading: false });
|
||||||
|
await loadMachineOptions();
|
||||||
|
reload();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.mixing-step-history-picker-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-step-history-picker-label {
|
||||||
|
color: #333;
|
||||||
|
font-size: 13px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
/* 嵌套在全屏混炼示方弹窗之上,避免被父弹窗遮挡 */
|
||||||
|
.mixing-step-history-picker-modal-wrap {
|
||||||
|
.ant-modal {
|
||||||
|
top: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 机台下拉挂到 body,避免弹窗 overflow 裁剪;层级高于 Modal */
|
||||||
|
.mixing-step-history-picker-machine-dropdown {
|
||||||
|
z-index: 2100 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<a-select
|
||||||
|
:value="row[field]"
|
||||||
|
:options="options"
|
||||||
|
:disabled="disabled"
|
||||||
|
:open="dropdownOpen"
|
||||||
|
allow-clear
|
||||||
|
show-search
|
||||||
|
:bordered="false"
|
||||||
|
size="small"
|
||||||
|
class="mixing-step-select"
|
||||||
|
popup-class-name="mixing-step-select-dropdown"
|
||||||
|
:list-height="listHeight"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:get-popup-container="getPopupContainer"
|
||||||
|
@update:value="handleChange"
|
||||||
|
@dropdown-visible-change="handleDropdownVisibleChange"
|
||||||
|
@click.stop
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
|
||||||
|
/** 下拉单项高度(与 ant-design-vue small Select 选项行高一致) */
|
||||||
|
const STEP_SELECT_ITEM_HEIGHT = 32;
|
||||||
|
/** 下拉最多可见条数 */
|
||||||
|
const STEP_SELECT_MAX_VISIBLE = 20;
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
row: Recordable;
|
||||||
|
field: string;
|
||||||
|
options: { label: string; value: string }[];
|
||||||
|
disabled?: boolean;
|
||||||
|
placeholder?: string;
|
||||||
|
machineId?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
const dropdownOpen = ref(false);
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260525 for:【XSLMES-20260525-A57】混合步骤动作/组合下拉最多展示20条-----------
|
||||||
|
const listHeight = computed(() => {
|
||||||
|
const count = props.options?.length ?? 0;
|
||||||
|
const visibleCount = count > 0 ? Math.min(count, STEP_SELECT_MAX_VISIBLE) : STEP_SELECT_MAX_VISIBLE;
|
||||||
|
return visibleCount * STEP_SELECT_ITEM_HEIGHT;
|
||||||
|
});
|
||||||
|
//update-end---author:cursor ---date:20260525 for:【XSLMES-20260525-A57】混合步骤动作/组合下拉最多展示20条-----------
|
||||||
|
|
||||||
|
function handleChange(value: string | undefined) {
|
||||||
|
props.row[props.field] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A37】未选机台点击动作/组合提示请先选择机台-----------
|
||||||
|
function handleDropdownVisibleChange(visible: boolean) {
|
||||||
|
if (props.disabled) {
|
||||||
|
dropdownOpen.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (visible && !props.machineId) {
|
||||||
|
createMessage.warning('请先选择机台');
|
||||||
|
dropdownOpen.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dropdownOpen.value = visible;
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A37】未选机台点击动作/组合提示请先选择机台-----------
|
||||||
|
|
||||||
|
//update-begin---author:cursor ---date:20260522 for:【XSLMES-20260522-A36】动作/组合下拉挂到body避免被表格裁切-----------
|
||||||
|
function getPopupContainer() {
|
||||||
|
return document.body;
|
||||||
|
}
|
||||||
|
//update-end---author:cursor ---date:20260522 for:【XSLMES-20260522-A36】动作/组合下拉挂到body避免被表格裁切-----------
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.mixing-step-select {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
:deep(.ant-select) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-select-selector) {
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
background: transparent !important;
|
||||||
|
padding: 0 18px 0 2px !important;
|
||||||
|
min-height: 24px !important;
|
||||||
|
height: 100% !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-select-selection-item),
|
||||||
|
:deep(.ant-select-selection-placeholder) {
|
||||||
|
line-height: 1.2 !important;
|
||||||
|
text-align: center;
|
||||||
|
padding-inline-end: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-select-selection-search-input) {
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-select-arrow) {
|
||||||
|
right: 2px;
|
||||||
|
margin-top: -3px;
|
||||||
|
color: #666;
|
||||||
|
font-size: 10px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-select-clear) {
|
||||||
|
right: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
<template>
|
||||||
|
<Popover
|
||||||
|
v-model:open="popoverOpen"
|
||||||
|
trigger="click"
|
||||||
|
placement="bottomRight"
|
||||||
|
:overlayClassName="`${prefixCls}__popover`"
|
||||||
|
@open-change="handleOpenChange"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<div :class="`${prefixCls}__title`">{{ meta.label }} - 行高设置</div>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<div :class="`${prefixCls}__form`">
|
||||||
|
<div :class="`${prefixCls}__field`">
|
||||||
|
<span class="field-label">行高(px)</span>
|
||||||
|
<InputNumber
|
||||||
|
v-model:value="draftRowHeight"
|
||||||
|
:min="MIXING_TABLE_ROW_HEIGHT_MIN"
|
||||||
|
:max="MIXING_TABLE_ROW_HEIGHT_MAX"
|
||||||
|
:step="1"
|
||||||
|
size="small"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div :class="`${prefixCls}__field`">
|
||||||
|
<span class="field-label">展示行数</span>
|
||||||
|
<InputNumber
|
||||||
|
v-model:value="draftVisibleRowCount"
|
||||||
|
:min="meta.minVisibleRowCount"
|
||||||
|
:max="meta.maxVisibleRowCount"
|
||||||
|
:step="1"
|
||||||
|
size="small"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div :class="`${prefixCls}__hint`">展示行数为列表可视区域高度,数据超出时可滚动查看。</div>
|
||||||
|
</div>
|
||||||
|
<div :class="`${prefixCls}__footer`">
|
||||||
|
<a-button size="small" @click="handleReset">重置</a-button>
|
||||||
|
<a-button size="small" type="primary" @click="handleSave">保存</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<a-tooltip title="行高设置">
|
||||||
|
<a-button size="small" :class="`${prefixCls}-btn`" @click.stop>
|
||||||
|
<Icon icon="ant-design:column-height-outlined" />
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</Popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, type PropType } from 'vue';
|
||||||
|
import { Popover, InputNumber } from 'ant-design-vue';
|
||||||
|
import { Icon } from '/@/components/Icon';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import {
|
||||||
|
MIXING_TABLE_HEIGHT_SETTING_META,
|
||||||
|
MIXING_TABLE_ROW_HEIGHT_MAX,
|
||||||
|
MIXING_TABLE_ROW_HEIGHT_MIN,
|
||||||
|
getMixingTableHeightDefault,
|
||||||
|
normalizeMixingTableHeightPreference,
|
||||||
|
saveMixingTableHeightPreference,
|
||||||
|
type MixingDetailTableKey,
|
||||||
|
type MixingTableHeightPreference,
|
||||||
|
} from '../MesXslMixingSpec.data';
|
||||||
|
|
||||||
|
const prefixCls = 'mixing-table-row-height-setting';
|
||||||
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
tableKey: {
|
||||||
|
type: String as PropType<MixingDetailTableKey>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
preference: {
|
||||||
|
type: Object as PropType<MixingTableHeightPreference>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:preference', value: MixingTableHeightPreference): void;
|
||||||
|
(e: 'change', value: MixingTableHeightPreference): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const popoverOpen = ref(false);
|
||||||
|
const meta = computed(() => MIXING_TABLE_HEIGHT_SETTING_META[props.tableKey]);
|
||||||
|
const draftRowHeight = ref(meta.value.defaultRowHeight);
|
||||||
|
const draftVisibleRowCount = ref(meta.value.defaultVisibleRowCount);
|
||||||
|
|
||||||
|
function syncDraftFromPreference(preference: MixingTableHeightPreference) {
|
||||||
|
const normalized = normalizeMixingTableHeightPreference(props.tableKey, preference);
|
||||||
|
draftRowHeight.value = normalized.rowHeight;
|
||||||
|
draftVisibleRowCount.value = normalized.visibleRowCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOpenChange(open: boolean) {
|
||||||
|
if (open) {
|
||||||
|
syncDraftFromPreference(props.preference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReset() {
|
||||||
|
syncDraftFromPreference(getMixingTableHeightDefault(props.tableKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSave() {
|
||||||
|
const next = normalizeMixingTableHeightPreference(props.tableKey, {
|
||||||
|
rowHeight: draftRowHeight.value,
|
||||||
|
visibleRowCount: draftVisibleRowCount.value,
|
||||||
|
});
|
||||||
|
saveMixingTableHeightPreference(props.tableKey, next);
|
||||||
|
emit('update:preference', next);
|
||||||
|
emit('change', next);
|
||||||
|
createMessage.success('保存成功');
|
||||||
|
popoverOpen.value = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.mixing-table-row-height-setting-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding-inline: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.mixing-table-row-height-setting__popover {
|
||||||
|
.mixing-table-row-height-setting__title {
|
||||||
|
min-width: 180px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-table-row-height-setting__form {
|
||||||
|
width: 220px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-table-row-height-setting__field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.field-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #595959;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-table-row-height-setting__hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #8c8c8c;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mixing-table-row-height-setting__footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
padding-top: 4px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -18,7 +18,17 @@
|
|||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"java.compile.nullAnalysis.mode": "automatic",
|
"java.compile.nullAnalysis.mode": "automatic",
|
||||||
"java.configuration.updateBuildConfiguration": "interactive",
|
"java.import.maven.enabled": true,
|
||||||
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx4G -Xms100m -Xlog:disable"
|
"java.configuration.updateBuildConfiguration": "automatic",
|
||||||
|
"java.autobuild.enabled": true,
|
||||||
|
"java.import.maven.offline.enabled": false,
|
||||||
|
"java.configuration.maven.notCoveredPluginExecutionSeverity": "ignore",
|
||||||
|
"java.jdt.ls.java.home": "C:\\Program Files\\Java\\jdk-17",
|
||||||
|
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx4G -Xms100m -Xlog:disable",
|
||||||
|
"java.import.exclusions": [
|
||||||
|
"**/jeecg-server-cloud/**",
|
||||||
|
"**/jeecg-boot-platform/**",
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user