diff --git a/docs/double-rack-ddl.sql b/docs/double-rack-ddl.sql
new file mode 100644
index 00000000..74382905
--- /dev/null
+++ b/docs/double-rack-ddl.sql
@@ -0,0 +1,81 @@
+-- 双机架 (double-rack) 数据库 DDL
+-- 在 jdbc:mysql://140.143.206.120:13306/double-rack 上执行
+
+-- 工艺方案主表
+CREATE TABLE IF NOT EXISTS `mill_process_recipe` (
+ `recipe_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `recipe_no` VARCHAR(64) NOT NULL COMMENT '方案记录号(唯一)',
+ `alloy_no` VARCHAR(32) NOT NULL COMMENT '合金号',
+ `pass_count` INT NOT NULL DEFAULT 0 COMMENT '道次数量',
+ `in_thick` DECIMAL(8,3) DEFAULT NULL COMMENT '原料厚度(mm)',
+ `out_thick` DECIMAL(8,3) DEFAULT NULL COMMENT '成品厚度(mm)',
+ `out_width` DECIMAL(8,1) DEFAULT NULL COMMENT '成品宽度(mm)',
+ `status` CHAR(1) NOT NULL DEFAULT '0' COMMENT '状态: 0-正常 1-停用',
+ `del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标志: 0-存在 2-删除',
+ `create_by` VARCHAR(64) DEFAULT NULL,
+ `create_time` DATETIME DEFAULT NULL,
+ `update_by` VARCHAR(64) DEFAULT NULL,
+ `update_time` DATETIME DEFAULT NULL,
+ `remark` VARCHAR(512) DEFAULT NULL,
+ PRIMARY KEY (`recipe_id`),
+ UNIQUE KEY `uk_recipe_no` (`recipe_no`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='双机架工艺方案主表';
+
+-- 工艺方案道次表
+CREATE TABLE IF NOT EXISTS `mill_process_pass` (
+ `pass_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `recipe_id` BIGINT NOT NULL COMMENT '关联方案ID',
+ `pass_no` INT NOT NULL COMMENT '道次序号',
+ `in_thick` DECIMAL(8,3) DEFAULT NULL COMMENT '入口厚度(mm)',
+ `out_thick` DECIMAL(8,3) DEFAULT NULL COMMENT '出口厚度(mm)',
+ `width` DECIMAL(8,1) DEFAULT NULL COMMENT '宽度(mm)',
+ `roll_force` DECIMAL(10,2) DEFAULT NULL COMMENT '轧制力(kN)',
+ `in_tension` DECIMAL(10,2) DEFAULT NULL COMMENT '入口张力(kN)',
+ `out_tension` DECIMAL(10,2) DEFAULT NULL COMMENT '出口张力(kN)',
+ `max_speed` DECIMAL(8,2) DEFAULT NULL COMMENT '最高速度(m/min)',
+ `in_unit_tension` DECIMAL(10,4) DEFAULT NULL COMMENT '入口单位张力(N/mm²)',
+ `out_unit_tension` DECIMAL(10,4) DEFAULT NULL COMMENT '出口单位张力(N/mm²)',
+ `reduction` DECIMAL(8,3) DEFAULT NULL COMMENT '压下量(mm)',
+ `total_reduction` DECIMAL(8,3) DEFAULT NULL COMMENT '总压下量(mm)',
+ `del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标志',
+ `create_by` VARCHAR(64) DEFAULT NULL,
+ `create_time` DATETIME DEFAULT NULL,
+ `update_by` VARCHAR(64) DEFAULT NULL,
+ `update_time` DATETIME DEFAULT NULL,
+ `remark` VARCHAR(512) DEFAULT NULL,
+ PRIMARY KEY (`pass_id`),
+ KEY `idx_recipe_id` (`recipe_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='双机架工艺方案道次表';
+
+-- 生产计划表(轧制队列)
+CREATE TABLE IF NOT EXISTS `mill_production_plan` (
+ `plan_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `plan_no` VARCHAR(64) NOT NULL COMMENT '计划号',
+ `plan_status` CHAR(1) NOT NULL DEFAULT '0' COMMENT '计划状态: 0-待生产 1-生产中 2-完成 3-撤销',
+ `prod_status` VARCHAR(16) NOT NULL DEFAULT 'Idle' COMMENT '生产状态: Idle/Rolling/NextCoil/Done/Error',
+ `sort_no` INT NOT NULL DEFAULT 0 COMMENT '队列序号',
+ `in_mat_no` VARCHAR(64) DEFAULT NULL COMMENT '钢卷编号(入场钢卷号)',
+ `sg_sign` VARCHAR(64) DEFAULT NULL COMMENT '合金牌号',
+ `in_mat_thick` DECIMAL(8,3) DEFAULT NULL COMMENT '采料厚度(mm)',
+ `in_mat_width` DECIMAL(8,1) DEFAULT NULL COMMENT '采料宽度(mm)',
+ `in_mat_wt` DECIMAL(10,3) DEFAULT NULL COMMENT '采料重量(t)',
+ `in_mat_len` DECIMAL(10,2) DEFAULT NULL COMMENT '采料长度(m)',
+ `in_mat_in_dia` DECIMAL(8,1) DEFAULT NULL COMMENT '采料内径(mm)',
+ `in_mat_dia` DECIMAL(8,1) DEFAULT NULL COMMENT '采料外径(mm)',
+ `out_thick` DECIMAL(8,3) DEFAULT NULL COMMENT '成品厚度(mm)',
+ `pass_count` INT NOT NULL DEFAULT 0 COMMENT '道次数',
+ `recipe_id` BIGINT DEFAULT NULL COMMENT '关联工艺方案ID',
+ `recipe_no` VARCHAR(64) DEFAULT NULL COMMENT '工艺方案号',
+ `enter_coil_no` VARCHAR(64) DEFAULT NULL COMMENT '关联三级入场钢卷号',
+ `current_coil_no` VARCHAR(64) DEFAULT NULL COMMENT '关联三级当前钢卷号',
+ `del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标志',
+ `create_by` VARCHAR(64) DEFAULT NULL,
+ `create_time` DATETIME DEFAULT NULL,
+ `update_by` VARCHAR(64) DEFAULT NULL,
+ `update_time` DATETIME DEFAULT NULL,
+ `remark` VARCHAR(512) DEFAULT NULL,
+ PRIMARY KEY (`plan_id`),
+ KEY `idx_in_mat_no` (`in_mat_no`),
+ KEY `idx_enter_coil_no` (`enter_coil_no`),
+ KEY `idx_current_coil_no` (`current_coil_no`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='双机架生产计划表(轧制队列)';
diff --git a/klp-admin/src/main/resources/application-dev.yml b/klp-admin/src/main/resources/application-dev.yml
index a5fe3783..38d92067 100644
--- a/klp-admin/src/main/resources/application-dev.yml
+++ b/klp-admin/src/main/resources/application-dev.yml
@@ -98,6 +98,14 @@ spring:
url: jdbc:mysql://140.143.206.120:3306/cgldb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: klp
password: KeLunPu123@
+ # 双机架数据源
+ double-rack:
+ lazy: true
+ type: ${spring.datasource.type}
+ driverClassName: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://140.143.206.120:13306/double-rack?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
+ username: klp
+ password: KeLunPu@123
# Oracle 数据源
acid-l2:
lazy: true
@@ -167,7 +175,7 @@ redisson:
# 客户端名称
clientName: ${klp.name}
# 最小空闲连接数
- connectionMinimumIdleSize: 8
+ connectionMinimumIdleSize: 4
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
diff --git a/klp-admin/src/main/resources/application-prod.yml b/klp-admin/src/main/resources/application-prod.yml
index 5a18a336..f4555360 100644
--- a/klp-admin/src/main/resources/application-prod.yml
+++ b/klp-admin/src/main/resources/application-prod.yml
@@ -103,6 +103,15 @@ spring:
password: root
hikari:
connectionTestQuery: SELECT 1 FROM DUAL
+
+ # 双机架数据源
+ double-rack:
+ lazy: true
+ type: ${spring.datasource.type}
+ driverClassName: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://140.143.206.120:13306/double-rack?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
+ username: klp
+ password: KeLunPu@123
# postgres:
# type: ${spring.datasource.type}
# driverClassName: org.postgresql.Driver
diff --git a/klp-ui/src/api/wms/drMill.js b/klp-ui/src/api/wms/drMill.js
new file mode 100644
index 00000000..83868bd2
--- /dev/null
+++ b/klp-ui/src/api/wms/drMill.js
@@ -0,0 +1,100 @@
+import request from '@/utils/request'
+
+// ── 双机架工艺规程 ──
+
+export function listDrRecipe(params) {
+ return request({ url: '/dr/mill/recipe/list', method: 'get', params })
+}
+
+export function getDrRecipeDetail(id) {
+ return request({ url: `/dr/mill/recipe/${id}`, method: 'get' })
+}
+
+export function addDrRecipe(data) {
+ return request({ url: '/dr/mill/recipe', method: 'post', data })
+}
+
+export function updateDrRecipe(data) {
+ return request({ url: '/dr/mill/recipe', method: 'put', data })
+}
+
+export function delDrRecipe(ids) {
+ return request({ url: `/dr/mill/recipe/${ids}`, method: 'delete' })
+}
+
+// ── 双机架工艺规程版本 ──
+
+export function listDrRecipeVersions(recipeId) {
+ return request({ url: `/dr/mill/recipe/version/list/${recipeId}`, method: 'get' })
+}
+
+export function getDrRecipeVersionDetail(versionId) {
+ return request({ url: `/dr/mill/recipe/version/${versionId}`, method: 'get' })
+}
+
+export function addDrRecipeVersion(data) {
+ return request({ url: '/dr/mill/recipe/version', method: 'post', data })
+}
+
+export function updateDrRecipeVersion(data) {
+ return request({ url: '/dr/mill/recipe/version', method: 'put', data })
+}
+
+export function activateDrRecipeVersion(versionId) {
+ return request({ url: `/dr/mill/recipe/version/activate/${versionId}`, method: 'put' })
+}
+
+export function delDrRecipeVersion(versionId) {
+ return request({ url: `/dr/mill/recipe/version/${versionId}`, method: 'delete' })
+}
+
+// ── 双机架生产计划 ──
+
+export function listDrPlan(params) {
+ return request({ url: '/dr/mill/plan/list', method: 'get', params })
+}
+
+export function addDrPlan(data) {
+ return request({ url: '/dr/mill/plan', method: 'post', data })
+}
+
+export function updateDrPlan(data) {
+ return request({ url: '/dr/mill/plan', method: 'put', data })
+}
+
+export function delDrPlan(id) {
+ return request({ url: `/dr/mill/plan/${id}`, method: 'delete' })
+}
+
+export function getDrPlanByActionId(actionId) {
+ return request({ url: `/dr/mill/plan/byAction/${actionId}`, method: 'get' })
+}
+
+/** 实绩分页查询(double-rack 库,按创建时间倒序) */
+export function listDrActualPage(params) {
+ return request({ url: '/dr/mill/plan/actual/page', method: 'get', params })
+}
+
+export function moveUpDrPlan(id) {
+ return request({ url: `/dr/mill/plan/moveUp/${id}`, method: 'put' })
+}
+
+export function moveDownDrPlan(id) {
+ return request({ url: `/dr/mill/plan/moveDown/${id}`, method: 'put' })
+}
+
+export function finishDrPlan(id) {
+ return request({ url: `/dr/mill/plan/finish/${id}`, method: 'put' })
+}
+
+// ── WMS 钢卷号查询(供计划绑定) ──
+
+export function queryCoilByNo(coilNo) {
+ return request({ url: '/wms/materialCoil/queryByCoilNo', method: 'get', params: { coilNo } })
+}
+
+// ── 双机架操作录入(保存 coilWarehouseOperationLog) ──
+
+import { addCoilWarehouseOperationLog, listCoilWarehouseOperationLog } from '@/api/wms/coilWarehouseOperationLog'
+
+export { addCoilWarehouseOperationLog, listCoilWarehouseOperationLog }
diff --git a/klp-ui/src/layout/components/TagsView/ScrollPane.vue b/klp-ui/src/layout/components/TagsView/ScrollPane.vue
index f92d99b7..b7251076 100644
--- a/klp-ui/src/layout/components/TagsView/ScrollPane.vue
+++ b/klp-ui/src/layout/components/TagsView/ScrollPane.vue
@@ -88,6 +88,12 @@ export default {
}
.el-scrollbar__wrap {
height: 39px;
+ overflow-x: auto;
+ overflow-y: hidden;
+ }
+ .el-scrollbar__view {
+ display: inline-block; /* 让所有 tag 排在同一行,不换行 */
+ white-space: nowrap;
}
}
}
diff --git a/klp-ui/src/layout/components/TagsView/index.vue b/klp-ui/src/layout/components/TagsView/index.vue
index 3d898700..d780c960 100644
--- a/klp-ui/src/layout/components/TagsView/index.vue
+++ b/klp-ui/src/layout/components/TagsView/index.vue
@@ -245,7 +245,7 @@ export default {
// background: #454c51;
border-bottom: 1px solid #a0a6ad;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.05) inset;
-
+
.tags-view-wrapper {
.tags-view-item {
display: inline-block;
@@ -253,6 +253,7 @@ export default {
cursor: pointer;
height: 26px;
line-height: 26px;
+ white-space: nowrap;
border: 1px solid #a0a6ad;
color: #111;
// 标签金属渐变背景
@@ -262,32 +263,32 @@ export default {
margin-left: 5px;
margin-top: 4px;
border-radius: 4px;
- box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1),
+ box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1),
-1px -1px 2px rgba(255, 255, 255, 0.05);
transition: all 0.2s ease;
-
+
&:first-of-type {
margin-left: 15px;
}
-
+
&:last-of-type {
margin-right: 15px;
}
-
+
&:hover {
- box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.15),
+ box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.15),
-1px -1px 2px rgba(255, 255, 255, 0.08);
border-color: #8d939b;
}
-
+
&.active {
// 激活状态主色调渐变
background: linear-gradient(145deg, #6b809d, #637994);
color: #fff;
border-color: #5a6d86;
- box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.15),
+ box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.15),
-1px -1px 2px rgba(255, 255, 255, 0.1) inset;
-
+
&::before {
content: '';
background: rgba(255, 255, 255, 0.8);
@@ -302,7 +303,7 @@ export default {
}
}
}
-
+
.contextmenu {
margin: 0;
// 右键菜单金属背景
@@ -317,15 +318,15 @@ export default {
font-size: 12px;
font-weight: 400;
color: #606266;
- box-shadow: 3px 3px 6px rgba(0, 0, 0, 0.15),
+ box-shadow: 3px 3px 6px rgba(0, 0, 0, 0.15),
-2px -2px 5px rgba(255, 255, 255, 0.08);
-
+
li {
margin: 0;
padding: 7px 16px;
cursor: pointer;
transition: all 0.2s ease;
-
+
&:hover {
background: rgba(99, 121, 148, 0.15);
color: #637994;
@@ -349,13 +350,13 @@ export default {
transition: all .3s cubic-bezier(.645, .045, .355, 1);
transform-origin: 100% 50%;
margin-left: 4px;
-
+
&:before {
transform: scale(.6);
display: inline-block;
vertical-align: -3px;
}
-
+
&:hover {
background-color: rgba(0, 0, 0, 0.15);
color: #ddd;
@@ -363,7 +364,7 @@ export default {
inset -1px -1px 2px rgba(255, 255, 255, 0.05);
}
}
-
+
&.active {
.el-icon-close:hover {
background-color: rgba(255, 255, 255, 0.2);
@@ -372,4 +373,4 @@ export default {
}
}
}
-
\ No newline at end of file
+
diff --git a/klp-ui/src/views/micro/pages/dr/components/Actual.vue b/klp-ui/src/views/micro/pages/dr/components/Actual.vue
new file mode 100644
index 00000000..eb1f4fdc
--- /dev/null
+++ b/klp-ui/src/views/micro/pages/dr/components/Actual.vue
@@ -0,0 +1,468 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.enterCoilNo || row.inMatNo || '—' }}
+
+
+ {{ row.currentCoilNo || '—' }}
+
+
+ {{ row.alloyNo || '—' }}
+
+
+
+
+ {{ planStatusLabel(row.planStatus) }}
+
+
+
+
+
+
+ {{ row.prodStatus || '—' }}
+
+
+
+
+ {{ row.inMatThick || '—' }}
+
+
+ {{ row.inMatWidth || '—' }}
+
+
+ {{ row.inMatWeight || '—' }}
+
+
+
+ {{ row.outThick || '—' }}
+
+
+
+ {{ row.passCount || '—' }}
+
+
+ {{ row.recipeNo || '—' }}
+
+
+ {{ formatDate(row.createTime) }}
+
+
+ {{ row.createBy || '—' }}
+
+
+ {{ row.remark || '—' }}
+
+
+
+
+
+
+
+
+
+
+
+
查找
+
+
+ 钢卷号
+
+
+
+
+ 开始时间
+
+
+
+
+ 结束时间
+
+
+
+
+ 查找
+ 重置
+
+
+
+
+
+
计划详情
+
+
+ 计划号
+ {{ selectedRow.planNo }}
+
+
+ 入场卷号
+ {{ selectedRow.enterCoilNo || selectedRow.inMatNo || '—' }}
+
+
+ 出口卷号
+ {{ selectedRow.currentCoilNo || '—' }}
+
+
+ 合金牌号
+ {{ selectedRow.alloyNo || '—' }}
+
+
+ 来料厚
+ {{ selectedRow.inMatThick ? selectedRow.inMatThick + ' mm' : '—' }}
+
+
+ 来料宽
+ {{ selectedRow.inMatWidth ? selectedRow.inMatWidth + ' mm' : '—' }}
+
+
+ 来料重
+ {{ selectedRow.inMatWeight ? selectedRow.inMatWeight + ' t' : '—' }}
+
+
+ 来料长
+ {{ selectedRow.inMatLength ? selectedRow.inMatLength + ' m' : '—' }}
+
+
+ 成品厚
+ {{ selectedRow.outThick ? selectedRow.outThick + ' mm' : '—' }}
+
+
+ 道次数
+ {{ selectedRow.passCount || '—' }}
+
+
+ 工艺方案
+ {{ selectedRow.recipeNo || '—' }}
+
+
+ 计划状态
+
+
+ {{ planStatusLabel(selectedRow.planStatus) }}
+
+
+
+
+ 生产状态
+
+
+ {{ selectedRow.prodStatus || '—' }}
+
+
+
+
+ 创建人
+ {{ selectedRow.createBy || '—' }}
+
+
+ 创建时间
+ {{ formatDate(selectedRow.createTime) }}
+
+
+ 备注
+ {{ selectedRow.remark }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/micro/pages/dr/components/Plan.vue b/klp-ui/src/views/micro/pages/dr/components/Plan.vue
new file mode 100644
index 00000000..46e56f0b
--- /dev/null
+++ b/klp-ui/src/views/micro/pages/dr/components/Plan.vue
@@ -0,0 +1,516 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ prodStatusLabel(row.prodStatus) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 请在上方选择一条计划
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.reduction }}
+
+
+ {{ row.totalReduction }}
+
+
+
+
+
+
+
+
该计划尚未绑定工艺参数
+
+ 选择已有方案
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 不显示已完成
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+ 新增计划
+ 修改
+ 完成
+ 删除
+ Up 上移
+ Down 下移
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mm
+
+
+
+
+ mm
+
+
+
+
+ mm
+
+
+
+
+ t
+
+
+
+
+ m
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 确定
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 该方案暂无版本,请先在「规程」页新增版本
+
+
+
+
+ 取消
+ 确定绑定
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/micro/pages/dr/components/ProcessSpec.vue b/klp-ui/src/views/micro/pages/dr/components/ProcessSpec.vue
new file mode 100644
index 00000000..cd68086f
--- /dev/null
+++ b/klp-ui/src/views/micro/pages/dr/components/ProcessSpec.vue
@@ -0,0 +1,485 @@
+
+
+
+
+
+
+
+
+
+
+
+
{{ r.recipeNo }}
+
{{ r.alloyNo }} · {{ r.inThick }}→{{ r.outThick }}mm
+
+
暂无方案
+
+
+
+
+
+
+
+
+
+ {{ v.versionCode }}
+ 激活
+ 已发布
+ 草稿
+
+
{{ v.remark }}
+
+ 激活
+ 删除
+
+
+
暂无版本,请新增
+
请先选择方案
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.passNo }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.reduction }}
+
+
+ {{ row.totalReduction }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mm
+
+
+ mm
+
+
+ mm
+
+
+
+ 取消
+ 确定
+ 删除
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/micro/pages/dr/index.vue b/klp-ui/src/views/micro/pages/dr/index.vue
new file mode 100644
index 00000000..acbf332f
--- /dev/null
+++ b/klp-ui/src/views/micro/pages/dr/index.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/timing/acid/rollConfig.vue b/klp-ui/src/views/timing/acid/rollConfig.vue
new file mode 100644
index 00000000..3ce9290f
--- /dev/null
+++ b/klp-ui/src/views/timing/acid/rollConfig.vue
@@ -0,0 +1,355 @@
+
+
+
+
+
+
+
+
+ | 机架 |
+ 位置 |
+ 备 辊 |
+ 在线辊 |
+ 换辊参考 |
+
+
+
+ | 辊号 |
+ 外径(mm) |
+ 凸度 |
+ 粗糙度 |
+
+ 辊号 |
+ 上/下 |
+ 辊型 |
+ 直径(mm) |
+ 凸度 |
+ 粗糙度 |
+ 本次长度 |
+ 本次重量 |
+ 安装时间 |
+
+ 本次长度 |
+ 累计长度 |
+ 本次重量 |
+ 累计重量 |
+
+
+
+
+
+ |
+ {{ stand.name }}
+ |
+ {{ pos.label }} |
+
+
+ {{ sv(pos.standby, 'rollid') }} |
+ {{ nv(pos.standby, 'diameter') }} |
+ {{ nv(pos.standby, 'crown') }} |
+ {{ nv(pos.standby, 'rough') }} |
+
+
+ {{ sv(pos.online, 'rollid') }} |
+ {{ dispPos(pos.online && pos.online.position) }} |
+
+
+ {{ dispType(pos.online && pos.online.type) }}
+
+ |
+ {{ nv(pos.online, 'diameter') }} |
+ {{ nv(pos.online, 'crown') }} |
+ {{ nv(pos.online, 'rough') }} |
+ {{ iv(pos.online, 'rolled_length') }} |
+ {{ iv(pos.online, 'rolled_weight') }} |
+ {{ dv(pos.online, 'instal_time') }} |
+
+
+ {{ iv(pos.online, 'rolled_length') }} |
+ {{ iv(pos.online, 'total_rolled_length') }} |
+ {{ iv(pos.online, 'rolled_weight') }} |
+ {{ iv(pos.online, 'total_rolled_weight') }} |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/timing/acid/rollHistory.vue b/klp-ui/src/views/timing/acid/rollHistory.vue
new file mode 100644
index 00000000..c00b93f1
--- /dev/null
+++ b/klp-ui/src/views/timing/acid/rollHistory.vue
@@ -0,0 +1,273 @@
+
+
+
+
+
酸轧换辊历史
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+ {{ standName(row.standid) }}
+
+
+ {{ dispPos(row.position) }}
+
+
+
+ {{ dispType(row.type) }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ fmtDate(row.instal_time) }}
+
+
+ {{ fmtDate(row.deinstal_time) }}
+
+
+ {{ fmtDate(row.change_time) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/wms/coil/do/dr-normal.vue b/klp-ui/src/views/wms/coil/do/dr-normal.vue
new file mode 100644
index 00000000..874dc0b0
--- /dev/null
+++ b/klp-ui/src/views/wms/coil/do/dr-normal.vue
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 出口实绩
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 重置
+
+ 新增录入(同步创建计划)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ coilInfo.enterCoilNo }}
+ {{ coilInfo.currentCoilNo }}
+ {{ coilInfo.actualThickness }} mm
+ {{ coilInfo.actualWidth }} mm
+ {{ coilInfo.netWeight }} t
+ {{ coilInfo.length }} m
+ {{ coilInfo.qualityStatus }}
+ {{ coilInfo.materialType }}
+
+
+ 写入表单
+
+
+
+ 输入入场钢卷号后自动查询
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/wms/coil/do/dr-repair.vue b/klp-ui/src/views/wms/coil/do/dr-repair.vue
new file mode 100644
index 00000000..3c1bf4a1
--- /dev/null
+++ b/klp-ui/src/views/wms/coil/do/dr-repair.vue
@@ -0,0 +1,231 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 修复参数
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 重置
+
+ 新增修复录入(同步创建计划)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ coilInfo.enterCoilNo }}
+ {{ coilInfo.currentCoilNo }}
+ {{ coilInfo.actualThickness }} mm
+ {{ coilInfo.actualWidth }} mm
+ {{ coilInfo.netWeight }} t
+ {{ coilInfo.length }} m
+ {{ coilInfo.qualityStatus }}
+
+
+ 写入表单
+
+
+
+ 输入入场钢卷号后自动查询
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/wms/coil/panels/DrMatchPanel.vue b/klp-ui/src/views/wms/coil/panels/DrMatchPanel.vue
new file mode 100644
index 00000000..4646b7ce
--- /dev/null
+++ b/klp-ui/src/views/wms/coil/panels/DrMatchPanel.vue
@@ -0,0 +1,213 @@
+
+
+
+
+
+
+
+
+
+
+ 计划号
+ {{ plan.planNo }}
+
+
+ 合金牌号
+ {{ plan.alloyNo || '—' }}
+
+
+ 采料厚度
+ {{ plan.inMatThick != null ? plan.inMatThick + ' mm' : '—' }}
+
+
+ 成品厚度
+ {{ plan.outThick != null ? plan.outThick + ' mm' : '—' }}
+
+
+ 采料宽度
+ {{ plan.inMatWidth != null ? plan.inMatWidth + ' mm' : '—' }}
+
+
+ 采料重量
+ {{ plan.inMatWeight != null ? plan.inMatWeight + ' t' : '—' }}
+
+
+ 采料长度
+ {{ plan.inMatLength != null ? plan.inMatLength + ' m' : '—' }}
+
+
+ 绑定方案
+ {{ plan.recipeNo || '未绑定' }}
+
+
+
+
+
+ 写入计划数据(重量/宽度/长度/厚度)
+
+
+
+
+
未找到关联的双机架计划
+
+
+
+
+
+
+
+
+
+ {{ row.inThick != null ? row.inThick : '—' }}
+
+
+
+ {{ row.outThick != null ? row.outThick : '—' }}
+
+
+
+ {{ row.rollForce != null ? row.rollForce : '—' }}
+
+
+
+ 写入
+
+
+
+
+
↑ 通常选最后一道次的出口厚度作为成品实测厚度
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/wms/coil/typing.vue b/klp-ui/src/views/wms/coil/typing.vue
index 683c8f97..2eff8fe2 100644
--- a/klp-ui/src/views/wms/coil/typing.vue
+++ b/klp-ui/src/views/wms/coil/typing.vue
@@ -7,7 +7,7 @@
钢卷信息更新
-->
@@ -26,9 +26,10 @@
-
+
-
+
+
@@ -326,7 +327,8 @@ import AbnormalForm from './components/AbnormalForm';
import { generateCoilNoPrefix } from "@/utils/coil/coilNo";
import { addCoilContractRel } from "@/api/wms/coilContractRel";
import ContractSelect from "@/components/KLPService/ContractSelect";
-import L2MatchPanel from './panels/L2MatchPanel.vue';
+import L2MatchPanel from './panels/L2MatchPanel.vue'
+import DrMatchPanel from './panels/DrMatchPanel.vue';
export default {
@@ -340,6 +342,7 @@ export default {
AbnormalForm,
ContractSelect,
L2MatchPanel,
+ DrMatchPanel,
},
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
data() {
@@ -429,6 +432,7 @@ export default {
],
},
actionId: null,
+ actionType: null, // 待操作类型,504/524 = 双机架
acidPrefill: {
visible: false,
type: 'info',
@@ -462,6 +466,10 @@ export default {
l2HotCoilId() {
return (this.currentInfo && this.currentInfo.enterCoilNo) || ''
},
+ /** 是否双机架工序(actionType 504=正常 / 524=修复) */
+ isDrAction() {
+ return this.actionType === 504 || this.actionType === 524
+ },
// 动态显示标签
getItemLabel() {
if (this.updateForm.materialType === '成品') {
@@ -490,6 +498,11 @@ export default {
// 填写生产开始时间
this.$set(this.updateForm, 'productionStartTime', pendingActionRes.data.createTime)
+ // 记录操作类型(用于判断是否双机架工序)
+ if (pendingActionRes.data && pendingActionRes.data.actionType != null) {
+ this.actionType = pendingActionRes.data.actionType
+ }
+
if (coilId) {
await this.loadCoilInfo(coilId);
}
@@ -523,6 +536,20 @@ export default {
}
},
methods: {
+ /** 双机架计划/道次快捷写入 */
+ applyDrFill(data) {
+ if (data.outThick != null) this.$set(this.updateForm, 'actualThickness', parseFloat(data.outThick))
+ if (data.inMatWidth != null) this.$set(this.updateForm, 'actualWidth', parseFloat(data.inMatWidth))
+ if (data.inMatWeight != null) {
+ this.$set(this.updateForm, 'netWeight', parseFloat(data.inMatWeight))
+ this.$set(this.updateForm, 'grossWeight', parseFloat(data.inMatWeight))
+ }
+ if (data.inMatLength != null) {
+ this.$set(this.updateForm, 'actualLength', parseFloat(data.inMatLength))
+ this.$set(this.updateForm, 'length', parseFloat(data.inMatLength))
+ }
+ },
+
applyL2Fill(data) {
if (data.entry_weight != null) {
const w = parseFloat(data.entry_weight)
diff --git a/klp-ui/src/views/wms/mill/dr-plan.vue b/klp-ui/src/views/wms/mill/dr-plan.vue
new file mode 100644
index 00000000..b3f06c84
--- /dev/null
+++ b/klp-ui/src/views/wms/mill/dr-plan.vue
@@ -0,0 +1,385 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ prodStatusLabel(row.prodStatus) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 请在上方选择一条计划
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.reduction }}
+
+
+ {{ row.totalReduction }}
+
+
+
+
+
+
+
+
该计划尚未绑定工艺参数
+
+ 选择已有方案
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 不显示已完成
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+ 新增计划
+ 修改
+ 完成
+ 删除
+ Up 上移
+ Down 下移
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mm
+
+
+
+
+ mm
+
+
+
+
+ mm
+
+
+
+
+ t
+
+
+
+
+ m
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 确定
+
+
+
+
+
+
+
+
+
+ 取消
+ 确定绑定
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/wms/mill/dr-process.vue b/klp-ui/src/views/wms/mill/dr-process.vue
new file mode 100644
index 00000000..357981d4
--- /dev/null
+++ b/klp-ui/src/views/wms/mill/dr-process.vue
@@ -0,0 +1,461 @@
+
+
+
+
+
+
+
+
+
+
+
+
{{ r.recipeNo }}
+
{{ r.alloyNo }} · {{ r.inThick }}→{{ r.outThick }}mm
+
+ 编辑
+ 删除
+
+
+
暂无方案
+
+
+
+
+
+
+
+
+
+ {{ v.versionCode }}
+ 激活
+ 已发布
+ 草稿
+
+
{{ v.remark }}
+
+ 激活
+ 删除
+
+
+
暂无版本,请新增
+
请先选择方案
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.passNo }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.reduction }}
+
+
+ {{ row.totalReduction }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mm
+
+
+ mm
+
+
+ mm
+
+
+
+ 取消
+ 确定
+ 删除
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/wms/processSpec/planSpec.vue b/klp-ui/src/views/wms/processSpec/planSpec.vue
index 25035a53..51228f16 100644
--- a/klp-ui/src/views/wms/processSpec/planSpec.vue
+++ b/klp-ui/src/views/wms/processSpec/planSpec.vue
@@ -65,7 +65,7 @@
/>
-
点位名称:
+
参数名称:
新建参数
+ 新建方案点位
+ >管理点位
模板导入
-
+
-
-
- {{ segLabel(row.segmentType) }} › {{ row.segmentName || '—' }}
-
-
-
-
+
- 编辑
- 参数
- 删除
+ {{ row._segmentLabel }}
+
+
+
+
+
+
+
+
+
+
+
+ 异常
+
+
+ 正常
+
+ —
+
+
+
+
+ 编辑
+ 删除
-
-
-
-
-
-
-
-
- {{ row.actualSrcId || '—' }}
-
-
- {{ row.presetSrcId || '—' }}
-
-
-
-
-
-
- {{ (row.updateTime || row.createTime || '').substring(0, 16) || '—' }}
-
-
-
-
- 异常
-
-
- 正常
-
- —
-
-
-
-
- 编辑
- 删除
-
-
-
-
-
-
-
-
-
-
-
- {{ row.storedTarget != null ? row.storedTarget : '—' }}
-
-
- {{ row.storedUpper != null ? row.storedUpper : '—' }}
-
-
- {{ row.storedLower != null ? row.storedLower : '—' }}
-
-
-
-
- {{ row.actualMax != null ? row.actualMax : '—' }}
-
-
-
-
-
-
- {{ row.actualMin != null ? row.actualMin : '—' }}
-
-
-
-
-
- +{{ row.deviationMax }}
- —
-
-
-
-
- {{ row.deviationMin }}
- —
-
-
-
-
- {{ (row.detectedAt || '').substring(0, 16) || '—' }}
-
-
-
- 超上限
- 低于下限
-
-
-
-
-
-
-
-
@@ -361,6 +274,16 @@
+
+
+
+
+
@@ -488,7 +411,7 @@ const TEMPLATE_HEADERS = ['段类型', '段名称', '点位名称', '参数名
/** 表头字段映射 */
const HEADER_MAP = {
'段类型': 'segmentType',
- '段名称': 'segmentName',
+ '段名称': 'segmentName',
'点位名称': 'pointName',
'参数名称': 'paramName',
'设定值': 'targetValue',
@@ -514,9 +437,8 @@ export default {
appliedFilterName: '',
planList: [],
planLoading: false,
- selectedPlan: null,
- paramList: [],
- paramLoading: false,
+ allParamList: [],
+ allParamLoading: false,
planOpen: false,
planTitle: '',
planSubmitLoading: false,
@@ -531,6 +453,7 @@ export default {
paramSubmitLoading: false,
paramForm: {},
paramRules: {
+ planId: [{ required: true, message: '请选择所属点位', trigger: 'change' }],
paramCode: [{ required: true, message: '参数编码不能为空', trigger: 'blur' }],
paramName: [{ required: true, message: '参数名称不能为空', trigger: 'blur' }]
},
@@ -632,12 +555,6 @@ export default {
extra.sort((a, b) => String(a.label).localeCompare(String(b.label), 'zh-CN'))
return [...SEGMENT_FORM_OPTIONS, ...extra]
},
- /** 当前选中点位下的异常条目 */
- planAnomalies() {
- if (!this.selectedPlan) return []
- return this.allAnomalies.filter(a => a.paramCode === this.selectedPlan.pointCode ||
- this.paramList.some(p => p.paramCode === a.paramCode))
- },
/** paramCode → anomaly 的快速索引(用于状态列) */
paramAnomalyMap() {
const map = {}
@@ -648,45 +565,42 @@ export default {
if (!this.coilAnomalyCoilId) return []
return this.allAnomalies.filter(a => a.coilId === this.coilAnomalyCoilId)
},
- filteredPlans() {
+ /** 所有 plan 的参数平铺成一行,带 plan 的段/点位信息 */
+ flatRows() {
+ const SEG_LABELS = { INLET: '入口段', PROCESS: '工艺段', OUTLET: '出口段' }
+ const planMap = {}
+ for (const plan of this.planList) planMap[plan.planId] = plan
+ const rows = []
+ for (const param of this.allParamList) {
+ const plan = planMap[param.planId]
+ if (!plan) continue
+ rows.push({
+ ...param,
+ _planId: plan.planId,
+ _segmentType: plan.segmentType,
+ _segmentLabel: SEG_LABELS[plan.segmentType] || plan.segmentName || plan.segmentType,
+ _pointName: plan.pointName,
+ _sortOrder: plan.sortOrder || 0
+ })
+ }
+ rows.sort((a, b) => {
+ const s = (a._sortOrder || 0) - (b._sortOrder || 0)
+ return s !== 0 ? s : (a.paramId || 0) - (b.paramId || 0)
+ })
+ return rows
+ },
+ filteredFlatRows() {
const type = this.activeSegmentType
- const sub = this.activeSegmentName
- return this.planList.filter(p => {
- const typeOk =
- type === '' || type === undefined || type === null
- ? true
- : String(p.segmentType) === String(type)
- let nameOkSeg = true
- if (typeOk && type !== '' && type !== undefined && type !== null) {
- if (sub === '' || sub === undefined || sub === null) {
- nameOkSeg = true
- } else if (sub === '__EMPTY__') {
- const sn = p.segmentName != null ? String(p.segmentName).trim() : ''
- nameOkSeg = !sn
- } else {
- const sn = p.segmentName != null ? String(p.segmentName).trim() : ''
- nameOkSeg = sn === String(sub).trim()
- }
- }
- const nameOk = !this.appliedFilterName || (p.pointName || '').includes(this.appliedFilterName)
- return typeOk && nameOkSeg && nameOk
+ const name = this.appliedFilterName
+ return this.flatRows.filter(r => {
+ const typeOk = !type || String(r._segmentType) === String(type)
+ const nameOk = !name || (r.paramName || '').includes(name) || (r.paramCode || '').includes(name)
+ return typeOk && nameOk
})
}
},
watch: {
$route: { immediate: true, handler() { this.syncFromRoute() } },
- planAnomalies: {
- handler(list) {
- if (list.length && this.anomalyExpanded) {
- this.$nextTick(() => this.renderAnomalyChart())
- }
- }
- },
- anomalyExpanded(val) {
- if (val && this.planAnomalies.length) {
- this.$nextTick(() => this.renderAnomalyChart())
- }
- },
segmentTypeTabOptions: {
handler() {
const a = this.activeSegmentType
@@ -852,22 +766,26 @@ export default {
},
loadPlans() {
this.planLoading = true
- this.selectedPlan = null
- this.paramList = []
listProcessPlan({ versionId: this.versionId, pageNum: 1, pageSize: 500 }).then(res => {
this.planList = res.rows || []
+ this.loadAllParams()
}).catch(e => console.error(e)).finally(() => { this.planLoading = false })
},
- loadParams(planId) {
- this.paramLoading = true
- listProcessPlanParam({ planId, pageNum: 1, pageSize: 500 }).then(res => {
- this.paramList = res.rows || []
- }).catch(e => console.error(e)).finally(() => { this.paramLoading = false })
- },
- onPlanSelect(row) {
- if (!row) return
- this.selectedPlan = row
- this.loadParams(row.planId)
+ async loadAllParams() {
+ if (!this.planList.length) { this.allParamList = []; return }
+ this.allParamLoading = true
+ try {
+ const results = await Promise.all(
+ this.planList.map(plan =>
+ listProcessPlanParam({ planId: plan.planId, pageNum: 1, pageSize: 500 })
+ .then(res => res.rows || [])
+ .catch(() => [])
+ )
+ )
+ this.allParamList = results.flat()
+ } finally {
+ this.allParamLoading = false
+ }
},
applyFilter() { this.appliedFilterName = this.filterName },
resetFilter() {
@@ -921,28 +839,33 @@ export default {
}).catch(() => {})
},
openParamDialog(planRow, paramRow) {
- const targetPlan = planRow || this.selectedPlan
- if (!targetPlan) { this.$message.warning('请先选择一个方案点位'); return }
- if (!this.selectedPlan || this.selectedPlan.planId !== targetPlan.planId) {
- this.selectedPlan = targetPlan
- this.loadParams(targetPlan.planId)
- }
this.paramForm = paramRow
? { ...paramRow }
: {
- planId: targetPlan.planId,
- paramCode: undefined,
- paramName: undefined,
+ planId: planRow ? planRow.planId : undefined,
+ paramCode: undefined,
+ paramName: undefined,
targetValue: undefined,
- lowerLimit: undefined,
- upperLimit: undefined,
- unit: undefined,
- remark: undefined
+ lowerLimit: undefined,
+ upperLimit: undefined,
+ unit: undefined,
+ remark: undefined
}
this.paramTitle = paramRow ? '编辑方案参数' : '新建方案参数'
this.paramOpen = true
this.$nextTick(() => this.$refs.paramFormRef && this.$refs.paramFormRef.clearValidate())
},
+ editParamFromFlat(row) {
+ this.openParamDialog(null, row)
+ },
+ deleteParamFromFlat(row) {
+ this.$modal.confirm('确认删除该参数?').then(() => {
+ return delProcessPlanParam(row.paramId)
+ }).then(() => {
+ this.$modal.msgSuccess('删除成功')
+ this.loadAllParams()
+ }).catch(() => {})
+ },
submitParam() {
this.$refs.paramFormRef.validate(ok => {
if (!ok) return
@@ -951,18 +874,10 @@ export default {
req.then(() => {
this.$modal.msgSuccess('保存成功')
this.paramOpen = false
- this.loadParams(this.selectedPlan.planId)
+ this.loadAllParams()
}).catch(e => console.error(e)).finally(() => { this.paramSubmitLoading = false })
})
},
- removeParam(row) {
- this.$modal.confirm('确认删除该参数?').then(() => {
- return delProcessPlanParam(row.paramId)
- }).then(() => {
- this.$modal.msgSuccess('删除成功')
- this.loadParams(this.selectedPlan.planId)
- }).catch(() => {})
- },
// ===================== 导入相关方法 =====================
/**
* 打开导入对话框
@@ -1218,7 +1133,7 @@ export default {
async batchImport() {
// �照点位名称分组,每个点位创建一条记录,然后添加多个参数
const pointGroups = {}
-
+
// 分组处理
this.tableData.forEach(row => {
const pointKey = `${row.segmentType}_${row.segmentName}_${row.pointName}`
@@ -1249,12 +1164,12 @@ export default {
try {
await this.importOnePoint(group)
this.importedCount += group.params.length
-
+
// 更新进度
index += group.params.length
const currentProgress = Math.round((index / this.totalCount) * 100)
this.progress = currentProgress
-
+
await new Promise(resolve => setTimeout(resolve, 50))
} catch (error) {
throw new Error(`导入点位"${group.pointName}"失败:${error.message}`)
@@ -1275,7 +1190,7 @@ export default {
pointCode: group.pointCode,
sortOrder: 0
}
-
+
const planRes = await addProcessPlan(planParams)
if (planRes.code !== 200) {
throw new Error(`点位创建失败:${planRes.msg || '接口返回异常'}`)
@@ -1293,7 +1208,7 @@ export default {
lowerLimit: param.lowerLimit ? Number(param.lowerLimit) : null,
unit: param.unit
}
-
+
const paramRes = await addProcessPlanParam(paramParams)
if (paramRes.code !== 200) {
throw new Error(`参数"${param.paramName}"创建失败:${paramRes.msg || '接口返回异常'}`)
@@ -1354,7 +1269,7 @@ export default {
// 创建工作簿
const wb = XLSX.utils.book_new()
const ws = XLSX.utils.aoa_to_sheet(templateData)
-
+
// 设置列宽
ws['!cols'] = [
{ wch: 10 }, // 段类型
@@ -1366,7 +1281,7 @@ export default {
{ wch: 10 }, // 下限
{ wch: 10 } // 单位
]
-
+
XLSX.utils.book_append_sheet(wb, ws, '导入模板')
XLSX.writeFile(wb, '方案点位导入模板.xlsx')
},
@@ -1558,6 +1473,19 @@ export default {
.btn-danger { color: #f56c6c; }
+/* ── 段 chip ── */
+.seg-chip {
+ display: inline-block;
+ padding: 2px 7px;
+ border-radius: 10px;
+ font-size: 11px;
+ font-weight: 600;
+ white-space: nowrap;
+}
+.seg-inlet { background: #ecf5ff; color: #3a6ea8; border: 1px solid #b3d8ff; }
+.seg-process { background: #f0f9eb; color: #3a7a2a; border: 1px solid #b3e19d; }
+.seg-outlet { background: #fdf6ec; color: #a86a00; border: 1px solid #f5dab1; }
+
/* ── 偏差分析 ── */
.anomaly-section-header {
display: flex;
diff --git a/klp-wms/src/main/java/com/klp/controller/DrMillProcessRecipeController.java b/klp-wms/src/main/java/com/klp/controller/DrMillProcessRecipeController.java
new file mode 100644
index 00000000..b39ef854
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/controller/DrMillProcessRecipeController.java
@@ -0,0 +1,94 @@
+package com.klp.controller;
+
+import com.klp.common.core.controller.BaseController;
+import com.klp.common.core.domain.R;
+import com.klp.domain.DrMillProcessRecipe;
+import com.klp.domain.DrMillProcessRecipeVersion;
+import com.klp.service.IDrMillProcessRecipeService;
+import com.klp.service.IDrMillProcessRecipeVersionService;
+import com.klp.service.impl.DrRecipeSyncService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Collections;
+import java.util.List;
+
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/dr/mill/recipe")
+public class DrMillProcessRecipeController extends BaseController {
+
+ private final IDrMillProcessRecipeService recipeService;
+ private final IDrMillProcessRecipeVersionService versionService;
+ private final DrRecipeSyncService syncService;
+
+ // ─── 方案 ────────────────────────────────────────────────
+
+ @GetMapping("/list")
+ public R> list(DrMillProcessRecipe query) {
+ List list = recipeService.selectList(query);
+ // 每次查询时补齐缺失的 L3 工艺规程(幂等,已存在则跳过)
+ syncService.syncRecipesToSpec(list);
+ return R.ok(list);
+ }
+
+ @GetMapping("/{id}")
+ public R detail(@PathVariable Long id) {
+ return R.ok(recipeService.selectDetailById(id));
+ }
+
+ @PostMapping
+ public R add(@RequestBody DrMillProcessRecipe recipe) {
+ recipeService.save(recipe);
+ // 新增方案后立即同步 L3 工艺规程
+ syncService.syncRecipesToSpec(Collections.singletonList(recipe));
+ return R.ok(recipe.getRecipeId());
+ }
+
+ @PutMapping
+ public R edit(@RequestBody DrMillProcessRecipe recipe) {
+ recipeService.update(recipe);
+ return R.ok();
+ }
+
+ @DeleteMapping("/{ids}")
+ public R remove(@PathVariable Long[] ids) {
+ recipeService.deleteByIds(ids);
+ return R.ok();
+ }
+
+ // ─── 版本 ────────────────────────────────────────────────
+
+ @GetMapping("/version/list/{recipeId}")
+ public R> versionList(@PathVariable Long recipeId) {
+ return R.ok(versionService.listByRecipeId(recipeId));
+ }
+
+ @GetMapping("/version/{versionId}")
+ public R versionDetail(@PathVariable Long versionId) {
+ return R.ok(versionService.getDetailById(versionId));
+ }
+
+ @PostMapping("/version")
+ public R addVersion(@RequestBody DrMillProcessRecipeVersion version) {
+ return R.ok(versionService.save(version));
+ }
+
+ @PutMapping("/version")
+ public R editVersion(@RequestBody DrMillProcessRecipeVersion version) {
+ versionService.update(version);
+ return R.ok();
+ }
+
+ @PutMapping("/version/activate/{versionId}")
+ public R activate(@PathVariable Long versionId) {
+ versionService.activate(versionId);
+ return R.ok();
+ }
+
+ @DeleteMapping("/version/{versionId}")
+ public R deleteVersion(@PathVariable Long versionId) {
+ versionService.deleteById(versionId);
+ return R.ok();
+ }
+}
diff --git a/klp-wms/src/main/java/com/klp/controller/DrMillProductionPlanController.java b/klp-wms/src/main/java/com/klp/controller/DrMillProductionPlanController.java
new file mode 100644
index 00000000..e3a2ace9
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/controller/DrMillProductionPlanController.java
@@ -0,0 +1,83 @@
+package com.klp.controller;
+
+import com.klp.common.core.controller.BaseController;
+import com.klp.common.core.domain.R;
+import com.klp.common.core.page.TableDataInfo;
+import com.klp.domain.DrMillProductionPlan;
+import com.klp.service.IDrMillProductionPlanService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 双机架生产计划管理
+ */
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/dr/mill/plan")
+public class DrMillProductionPlanController extends BaseController {
+
+ private final IDrMillProductionPlanService planService;
+
+ @GetMapping("/list")
+ public R> list(DrMillProductionPlan query) {
+ return R.ok(planService.selectList(query));
+ }
+
+ /** 实绩分页查询(按创建时间倒序,支持卷号/状态/时间范围过滤) */
+ @GetMapping("/actual/page")
+ public TableDataInfo actualPage(DrMillProductionPlan query) {
+ return planService.selectPageList(query);
+ }
+
+ @GetMapping("/{id}")
+ public R detail(@PathVariable Long id) {
+ return R.ok(planService.selectById(id));
+ }
+
+ /**
+ * 通过待操作ID查询绑定计划(含道次),供录入页快捷写入
+ * planNo = "DR" + actionId
+ */
+ @GetMapping("/byAction/{actionId}")
+ public R getByActionId(@PathVariable Long actionId) {
+ return R.ok(planService.selectByActionId(actionId));
+ }
+
+ @PostMapping
+ public R add(@RequestBody DrMillProductionPlan plan) {
+ planService.insert(plan);
+ return R.ok();
+ }
+
+ @PutMapping
+ public R edit(@RequestBody DrMillProductionPlan plan) {
+ planService.update(plan);
+ return R.ok();
+ }
+
+ @DeleteMapping("/{id}")
+ public R remove(@PathVariable Long id) {
+ planService.deleteById(id);
+ return R.ok();
+ }
+
+ @PutMapping("/moveUp/{id}")
+ public R moveUp(@PathVariable Long id) {
+ planService.moveUp(id);
+ return R.ok();
+ }
+
+ @PutMapping("/moveDown/{id}")
+ public R moveDown(@PathVariable Long id) {
+ planService.moveDown(id);
+ return R.ok();
+ }
+
+ @PutMapping("/finish/{id}")
+ public R finish(@PathVariable Long id) {
+ planService.finish(id);
+ return R.ok();
+ }
+}
diff --git a/klp-wms/src/main/java/com/klp/controller/WmsMaterialCoilController.java b/klp-wms/src/main/java/com/klp/controller/WmsMaterialCoilController.java
index 3ebed3ce..6a3a21e1 100644
--- a/klp-wms/src/main/java/com/klp/controller/WmsMaterialCoilController.java
+++ b/klp-wms/src/main/java/com/klp/controller/WmsMaterialCoilController.java
@@ -616,6 +616,16 @@ public class WmsMaterialCoilController extends BaseController {
}
}
+ /**
+ * 根据入场钢卷号或当前钢卷号查询钢卷信息,供双机架计划绑定使用
+ *
+ * @param coilNo 入场钢卷号或当前钢卷号
+ */
+ @GetMapping("/queryByCoilNo")
+ public R queryByCoilNo(@NotBlank(message = "钢卷号不能为空") @RequestParam String coilNo) {
+ return R.ok(iWmsMaterialCoilService.queryByCoilNo(coilNo));
+ }
+
/**
* 冷硬卷切边统计
diff --git a/klp-wms/src/main/java/com/klp/domain/DrMillProcessPass.java b/klp-wms/src/main/java/com/klp/domain/DrMillProcessPass.java
new file mode 100644
index 00000000..e2a6abd5
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/domain/DrMillProcessPass.java
@@ -0,0 +1,33 @@
+package com.klp.domain;
+
+import lombok.Data;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/** 双机架工艺方案道次(对应 double-rack.mill_process_pass) */
+@Data
+public class DrMillProcessPass {
+
+ private Long passId;
+ private Long recipeId;
+ /** 所属版本 ID */
+ private Long versionId;
+ private Integer passNo;
+ private BigDecimal inThick;
+ private BigDecimal outThick;
+ private BigDecimal width;
+ private BigDecimal rollForce;
+ private BigDecimal inTension;
+ private BigDecimal outTension;
+ private BigDecimal maxSpeed;
+ private BigDecimal inUnitTension;
+ private BigDecimal outUnitTension;
+ private BigDecimal reduction;
+ private BigDecimal totalReduction;
+ private String delFlag;
+ private String createBy;
+ private Date createTime;
+ private String updateBy;
+ private Date updateTime;
+ private String remark;
+}
diff --git a/klp-wms/src/main/java/com/klp/domain/DrMillProcessRecipe.java b/klp-wms/src/main/java/com/klp/domain/DrMillProcessRecipe.java
new file mode 100644
index 00000000..5e1630df
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/domain/DrMillProcessRecipe.java
@@ -0,0 +1,31 @@
+package com.klp.domain;
+
+import lombok.Data;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/** 双机架工艺方案主表(对应 double-rack.mill_process_recipe) */
+@Data
+public class DrMillProcessRecipe {
+
+ private Long recipeId;
+ private String recipeNo;
+ private String alloyNo;
+ private Integer passCount;
+ private BigDecimal inThick;
+ private BigDecimal outThick;
+ private BigDecimal outWidth;
+ /** 0-正常 1-停用 */
+ private String status;
+ /** 0-存在 2-删除 */
+ private String delFlag;
+ private String createBy;
+ private Date createTime;
+ private String updateBy;
+ private Date updateTime;
+ private String remark;
+
+ /** 关联道次(非数据库字段) */
+ private List passList;
+}
diff --git a/klp-wms/src/main/java/com/klp/domain/DrMillProcessRecipeVersion.java b/klp-wms/src/main/java/com/klp/domain/DrMillProcessRecipeVersion.java
new file mode 100644
index 00000000..b76c98fd
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/domain/DrMillProcessRecipeVersion.java
@@ -0,0 +1,28 @@
+package com.klp.domain;
+
+import lombok.Data;
+import java.util.Date;
+import java.util.List;
+
+/** 双机架工艺方案版本(double-rack.mill_process_recipe_version) */
+@Data
+public class DrMillProcessRecipeVersion {
+
+ private Long versionId;
+ private Long recipeId;
+ /** 版本号,如 V1.0 */
+ private String versionCode;
+ /** 1=已激活 0=未激活 */
+ private Integer isActive;
+ /** 0=草稿 1=已发布 */
+ private String status;
+ private String createBy;
+ private Date createTime;
+ private String updateBy;
+ private Date updateTime;
+ private String remark;
+ private String delFlag;
+
+ /** 关联道次(非数据库字段) */
+ private List passList;
+}
diff --git a/klp-wms/src/main/java/com/klp/domain/DrMillProductionPlan.java b/klp-wms/src/main/java/com/klp/domain/DrMillProductionPlan.java
new file mode 100644
index 00000000..da89344b
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/domain/DrMillProductionPlan.java
@@ -0,0 +1,66 @@
+package com.klp.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 双机架生产计划(对应 double-rack.mill_production_plan)。
+ * enterCoilNo / currentCoilNo 用于绑定三级 WMS 钢卷数据。
+ */
+@Data
+public class DrMillProductionPlan {
+
+ private Long planId;
+ private String planNo;
+ /** 0-待生产 1-生产中 2-完成 3-撤销 */
+ private String planStatus;
+ /** Idle / Rolling / NextCoil / Done */
+ private String prodStatus;
+ private Integer sortNo;
+ private String inMatNo;
+ private String alloyNo;
+ private BigDecimal inMatThick;
+ private BigDecimal inMatWidth;
+ private BigDecimal inMatWeight;
+ private BigDecimal inMatLength;
+ private BigDecimal inMatId;
+ private BigDecimal inMatOd;
+ private BigDecimal outThick;
+ private Integer passCount;
+ private Long recipeId;
+ private String recipeNo;
+ /** 绑定的工艺版本 ID */
+ private Long versionId;
+ /** 关联三级 WMS 入场钢卷号 */
+ private String enterCoilNo;
+ /** 关联三级 WMS 当前钢卷号 */
+ private String currentCoilNo;
+ /** 绑定方案的道次列表(非DB字段,按需填充) */
+ private List passList;
+
+ private String delFlag;
+ private String createBy;
+ private Date createTime;
+ private String updateBy;
+ private Date updateTime;
+ private String remark;
+
+ // ── 非 DB 查询字段(分页 + 时间范围) ──────────────
+ @TableField(exist = false)
+ private Integer pageNum;
+ @TableField(exist = false)
+ private Integer pageSize;
+ @TableField(exist = false)
+ private String createStartTime;
+ @TableField(exist = false)
+ private String createEndTime;
+
+ public int getOffset() {
+ int num = (pageNum != null && pageNum > 0) ? pageNum : 1;
+ int size = (pageSize != null && pageSize > 0) ? pageSize : 50;
+ return (num - 1) * size;
+ }
+}
diff --git a/klp-wms/src/main/java/com/klp/mapper/DrMillProcessPassMapper.java b/klp-wms/src/main/java/com/klp/mapper/DrMillProcessPassMapper.java
new file mode 100644
index 00000000..021afd2c
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/mapper/DrMillProcessPassMapper.java
@@ -0,0 +1,21 @@
+package com.klp.mapper;
+
+import com.klp.domain.DrMillProcessPass;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface DrMillProcessPassMapper {
+ List selectByVersionId(Long versionId);
+ List selectByRecipeId(Long recipeId);
+ int insertBatch(List list);
+ int deleteByVersionId(Long versionId);
+ int deleteByRecipeId(Long recipeId);
+ /** 查出所有 version_id 为空的道次所属 recipe_id(去重) */
+ List selectDistinctRecipeIdsWithOrphanPasses();
+ /** 将指定方案下所有 version_id 为空的道次批量设置 version_id */
+ int updateVersionIdForOrphans(@Param("recipeId") Long recipeId,
+ @Param("versionId") Long versionId);
+}
diff --git a/klp-wms/src/main/java/com/klp/mapper/DrMillProcessRecipeMapper.java b/klp-wms/src/main/java/com/klp/mapper/DrMillProcessRecipeMapper.java
new file mode 100644
index 00000000..6851396f
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/mapper/DrMillProcessRecipeMapper.java
@@ -0,0 +1,14 @@
+package com.klp.mapper;
+
+import com.klp.domain.DrMillProcessRecipe;
+import org.apache.ibatis.annotations.Mapper;
+import java.util.List;
+
+@Mapper
+public interface DrMillProcessRecipeMapper {
+ List selectList(DrMillProcessRecipe query);
+ DrMillProcessRecipe selectById(Long recipeId);
+ int insert(DrMillProcessRecipe recipe);
+ int update(DrMillProcessRecipe recipe);
+ int deleteBatchByIds(Long[] ids);
+}
diff --git a/klp-wms/src/main/java/com/klp/mapper/DrMillProcessRecipeVersionMapper.java b/klp-wms/src/main/java/com/klp/mapper/DrMillProcessRecipeVersionMapper.java
new file mode 100644
index 00000000..c7b59b71
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/mapper/DrMillProcessRecipeVersionMapper.java
@@ -0,0 +1,24 @@
+package com.klp.mapper;
+
+import com.klp.domain.DrMillProcessRecipeVersion;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
+@Mapper
+public interface DrMillProcessRecipeVersionMapper {
+ List selectByRecipeId(Long recipeId);
+ /** 查询指定方案已有的 V1.0 版本(用于迁移幂等判断) */
+ DrMillProcessRecipeVersion selectV1ByRecipeId(@Param("recipeId") Long recipeId);
+ /** 查询指定方案当前激活版本 */
+ DrMillProcessRecipeVersion selectActiveByRecipeId(@Param("recipeId") Long recipeId);
+ DrMillProcessRecipeVersion selectById(Long versionId);
+ int insert(DrMillProcessRecipeVersion version);
+ int update(DrMillProcessRecipeVersion version);
+ int deleteById(Long versionId);
+ int deleteByRecipeIds(@Param("ids") Long[] ids);
+ /** 将同方案其他版本置为未激活 */
+ int deactivateOthers(@Param("recipeId") Long recipeId, @Param("versionId") Long versionId);
+ /** 激活指定版本 */
+ int activate(Long versionId);
+}
diff --git a/klp-wms/src/main/java/com/klp/mapper/DrMillProductionPlanMapper.java b/klp-wms/src/main/java/com/klp/mapper/DrMillProductionPlanMapper.java
new file mode 100644
index 00000000..e3b387d7
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/mapper/DrMillProductionPlanMapper.java
@@ -0,0 +1,21 @@
+package com.klp.mapper;
+
+import com.klp.domain.DrMillProductionPlan;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
+@Mapper
+public interface DrMillProductionPlanMapper {
+ List selectList(DrMillProductionPlan query);
+ /** 分页查询(配合 PageHelper 或手动 LIMIT/OFFSET) */
+ List selectPageList(DrMillProductionPlan query);
+ long countPageList(DrMillProductionPlan query);
+ DrMillProductionPlan selectById(Long planId);
+ DrMillProductionPlan selectByPlanNo(@Param("planNo") String planNo);
+ int insert(DrMillProductionPlan plan);
+ int update(DrMillProductionPlan plan);
+ int deleteById(Long planId);
+ int updateSortNo(@Param("planId") Long planId, @Param("sortNo") int sortNo);
+ int countByStatus(@Param("status") String status);
+}
diff --git a/klp-wms/src/main/java/com/klp/service/IDrMillProcessRecipeService.java b/klp-wms/src/main/java/com/klp/service/IDrMillProcessRecipeService.java
new file mode 100644
index 00000000..7af1bbb9
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/service/IDrMillProcessRecipeService.java
@@ -0,0 +1,12 @@
+package com.klp.service;
+
+import com.klp.domain.DrMillProcessRecipe;
+import java.util.List;
+
+public interface IDrMillProcessRecipeService {
+ List selectList(DrMillProcessRecipe query);
+ DrMillProcessRecipe selectDetailById(Long id);
+ int save(DrMillProcessRecipe recipe);
+ int update(DrMillProcessRecipe recipe);
+ int deleteByIds(Long[] ids);
+}
diff --git a/klp-wms/src/main/java/com/klp/service/IDrMillProcessRecipeVersionService.java b/klp-wms/src/main/java/com/klp/service/IDrMillProcessRecipeVersionService.java
new file mode 100644
index 00000000..048f24eb
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/service/IDrMillProcessRecipeVersionService.java
@@ -0,0 +1,13 @@
+package com.klp.service;
+
+import com.klp.domain.DrMillProcessRecipeVersion;
+import java.util.List;
+
+public interface IDrMillProcessRecipeVersionService {
+ List listByRecipeId(Long recipeId);
+ DrMillProcessRecipeVersion getDetailById(Long versionId);
+ Long save(DrMillProcessRecipeVersion version);
+ void update(DrMillProcessRecipeVersion version);
+ void activate(Long versionId);
+ void deleteById(Long versionId);
+}
diff --git a/klp-wms/src/main/java/com/klp/service/IDrMillProductionPlanService.java b/klp-wms/src/main/java/com/klp/service/IDrMillProductionPlanService.java
new file mode 100644
index 00000000..304cc756
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/service/IDrMillProductionPlanService.java
@@ -0,0 +1,20 @@
+package com.klp.service;
+
+import com.klp.common.core.page.TableDataInfo;
+import com.klp.domain.DrMillProductionPlan;
+import java.util.List;
+
+public interface IDrMillProductionPlanService {
+ List selectList(DrMillProductionPlan query);
+ /** 分页查询实绩(按创建时间倒序) */
+ TableDataInfo selectPageList(DrMillProductionPlan query);
+ DrMillProductionPlan selectById(Long id);
+ /** 通过待操作ID查计划(planNo = "DR" + actionId),并附带道次列表 */
+ DrMillProductionPlan selectByActionId(Long actionId);
+ int insert(DrMillProductionPlan plan);
+ int update(DrMillProductionPlan plan);
+ int deleteById(Long id);
+ int moveUp(Long id);
+ int moveDown(Long id);
+ int finish(Long id);
+}
diff --git a/klp-wms/src/main/java/com/klp/service/IWmsMaterialCoilService.java b/klp-wms/src/main/java/com/klp/service/IWmsMaterialCoilService.java
index 583716e2..ba5ad1cb 100644
--- a/klp-wms/src/main/java/com/klp/service/IWmsMaterialCoilService.java
+++ b/klp-wms/src/main/java/com/klp/service/IWmsMaterialCoilService.java
@@ -349,5 +349,10 @@ public interface IWmsMaterialCoilService {
* @param response HTTP响应对象
*/
void exportAbnormalReport(WmsMaterialCoilBo bo, HttpServletResponse response);
+
+ /**
+ * 根据入场钢卷号或当前钢卷号查询钢卷,供双机架计划绑定使用
+ */
+ com.klp.domain.vo.WmsMaterialCoilVo queryByCoilNo(String coilNo);
}
diff --git a/klp-wms/src/main/java/com/klp/service/impl/DrMigrationService.java b/klp-wms/src/main/java/com/klp/service/impl/DrMigrationService.java
new file mode 100644
index 00000000..4b4ff8b8
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/service/impl/DrMigrationService.java
@@ -0,0 +1,65 @@
+package com.klp.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.klp.domain.DrMillProcessRecipeVersion;
+import com.klp.mapper.DrMillProcessPassMapper;
+import com.klp.mapper.DrMillProcessRecipeVersionMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 双机架历史道次版本迁移
+ * 将所有 version_id IS NULL 的道次归入对应方案的 V1.0 版本
+ */
+@Slf4j
+@DS("double-rack")
+@RequiredArgsConstructor
+@Service
+public class DrMigrationService {
+
+ private final DrMillProcessPassMapper passMapper;
+ private final DrMillProcessRecipeVersionMapper versionMapper;
+
+ @Transactional(rollbackFor = Exception.class)
+ public void migrateOrphanPassesToV1() {
+ List recipeIds = passMapper.selectDistinctRecipeIdsWithOrphanPasses();
+ if (recipeIds.isEmpty()) {
+ log.info("[DR迁移] 无需迁移:所有道次已绑定版本");
+ return;
+ }
+
+ int newVersionCount = 0;
+ int migratedPassCount = 0;
+
+ for (Long recipeId : recipeIds) {
+ // 幂等:V1.0 已存在则复用,避免重复执行时重复创建
+ DrMillProcessRecipeVersion v1 = versionMapper.selectV1ByRecipeId(recipeId);
+ if (v1 == null) {
+ v1 = new DrMillProcessRecipeVersion();
+ v1.setRecipeId(recipeId);
+ v1.setVersionCode("V1.0");
+ v1.setIsActive(1); // 默认激活
+ v1.setStatus("1"); // 已发布
+ v1.setCreateBy("system");
+ v1.setUpdateBy("system");
+ v1.setRemark("系统启动时自动迁移历史数据");
+ versionMapper.insert(v1);
+ newVersionCount++;
+ log.info("[DR迁移] 方案 {} 新建 V1.0,versionId={}", recipeId, v1.getVersionId());
+ } else {
+ log.info("[DR迁移] 方案 {} 已有 V1.0(versionId={}),直接复用", recipeId, v1.getVersionId());
+ }
+
+ int rows = passMapper.updateVersionIdForOrphans(recipeId, v1.getVersionId());
+ migratedPassCount += rows;
+ log.info("[DR迁移] 方案 {} 迁移 {} 条道次 → versionId={}", recipeId, rows, v1.getVersionId());
+ }
+
+ log.info("[DR迁移] 完成:共处理方案 {} 个,新建版本 {} 个,迁移道次 {} 条",
+ recipeIds.size(), newVersionCount, migratedPassCount);
+ }
+}
diff --git a/klp-wms/src/main/java/com/klp/service/impl/DrMillProcessRecipeServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/DrMillProcessRecipeServiceImpl.java
new file mode 100644
index 00000000..5280a831
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/service/impl/DrMillProcessRecipeServiceImpl.java
@@ -0,0 +1,75 @@
+package com.klp.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.klp.common.helper.LoginHelper;
+import com.klp.domain.DrMillProcessRecipe;
+import com.klp.domain.DrMillProcessRecipeVersion;
+import com.klp.mapper.DrMillProcessPassMapper;
+import com.klp.mapper.DrMillProcessRecipeMapper;
+import com.klp.mapper.DrMillProcessRecipeVersionMapper;
+import com.klp.service.IDrMillProcessRecipeService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@DS("double-rack")
+@RequiredArgsConstructor
+@Service
+public class DrMillProcessRecipeServiceImpl implements IDrMillProcessRecipeService {
+
+ private final DrMillProcessRecipeMapper recipeMapper;
+ private final DrMillProcessPassMapper passMapper;
+ private final DrMillProcessRecipeVersionMapper versionMapper;
+
+ @Override
+ public List selectList(DrMillProcessRecipe query) {
+ return recipeMapper.selectList(query);
+ }
+
+ @Override
+ public DrMillProcessRecipe selectDetailById(Long id) {
+ DrMillProcessRecipe recipe = recipeMapper.selectById(id);
+ if (recipe != null) {
+ // 优先取激活版本的道次;无激活版本则返回空列表,避免多版本混合
+ DrMillProcessRecipeVersion active = versionMapper.selectActiveByRecipeId(id);
+ if (active != null) {
+ recipe.setPassList(passMapper.selectByVersionId(active.getVersionId()));
+ }
+ }
+ return recipe;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int save(DrMillProcessRecipe recipe) {
+ String user = LoginHelper.getUsername();
+ recipe.setCreateBy(user);
+ recipe.setUpdateBy(user);
+ recipeMapper.insert(recipe);
+ // 道次现在通过版本接口管理,不再直接挂在方案上
+ return 1;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int update(DrMillProcessRecipe recipe) {
+ recipe.setUpdateBy(LoginHelper.getUsername());
+ recipeMapper.update(recipe);
+ // 道次通过版本接口管理,不在此处操作
+ return 1;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int deleteByIds(Long[] ids) {
+ for (Long id : ids) {
+ // 级联删版本下的道次,再删版本,再删方案
+ passMapper.deleteByRecipeId(id);
+ versionMapper.deleteByRecipeIds(new Long[]{id});
+ }
+ return recipeMapper.deleteBatchByIds(ids);
+ }
+
+}
diff --git a/klp-wms/src/main/java/com/klp/service/impl/DrMillProcessRecipeVersionServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/DrMillProcessRecipeVersionServiceImpl.java
new file mode 100644
index 00000000..51489c83
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/service/impl/DrMillProcessRecipeVersionServiceImpl.java
@@ -0,0 +1,86 @@
+package com.klp.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.klp.common.helper.LoginHelper;
+import com.klp.domain.DrMillProcessPass;
+import com.klp.domain.DrMillProcessRecipeVersion;
+import com.klp.mapper.DrMillProcessPassMapper;
+import com.klp.mapper.DrMillProcessRecipeVersionMapper;
+import com.klp.service.IDrMillProcessRecipeVersionService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@DS("double-rack")
+@RequiredArgsConstructor
+@Service
+public class DrMillProcessRecipeVersionServiceImpl implements IDrMillProcessRecipeVersionService {
+
+ private final DrMillProcessRecipeVersionMapper versionMapper;
+ private final DrMillProcessPassMapper passMapper;
+
+ @Override
+ public List listByRecipeId(Long recipeId) {
+ return versionMapper.selectByRecipeId(recipeId);
+ }
+
+ @Override
+ public DrMillProcessRecipeVersion getDetailById(Long versionId) {
+ DrMillProcessRecipeVersion v = versionMapper.selectById(versionId);
+ if (v != null) {
+ v.setPassList(passMapper.selectByVersionId(versionId));
+ }
+ return v;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long save(DrMillProcessRecipeVersion version) {
+ String user = LoginHelper.getUsername();
+ version.setCreateBy(user);
+ version.setUpdateBy(user);
+ versionMapper.insert(version);
+ savePassList(version);
+ return version.getVersionId();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void update(DrMillProcessRecipeVersion version) {
+ version.setUpdateBy(LoginHelper.getUsername());
+ versionMapper.update(version);
+ passMapper.deleteByVersionId(version.getVersionId());
+ savePassList(version);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void activate(Long versionId) {
+ DrMillProcessRecipeVersion v = versionMapper.selectById(versionId);
+ if (v == null) throw new RuntimeException("版本不存在");
+ versionMapper.deactivateOthers(v.getRecipeId(), versionId);
+ versionMapper.activate(versionId);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteById(Long versionId) {
+ passMapper.deleteByVersionId(versionId);
+ versionMapper.deleteById(versionId);
+ }
+
+ private void savePassList(DrMillProcessRecipeVersion version) {
+ List list = version.getPassList();
+ if (list == null || list.isEmpty()) return;
+ String user = LoginHelper.getUsername();
+ for (DrMillProcessPass p : list) {
+ p.setRecipeId(version.getRecipeId());
+ p.setVersionId(version.getVersionId());
+ p.setCreateBy(user);
+ p.setUpdateBy(user);
+ }
+ passMapper.insertBatch(list);
+ }
+}
diff --git a/klp-wms/src/main/java/com/klp/service/impl/DrMillProductionPlanServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/DrMillProductionPlanServiceImpl.java
new file mode 100644
index 00000000..8d4f612e
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/service/impl/DrMillProductionPlanServiceImpl.java
@@ -0,0 +1,118 @@
+package com.klp.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.klp.common.core.page.TableDataInfo;
+import com.klp.common.helper.LoginHelper;
+import com.klp.domain.DrMillProductionPlan;
+import com.klp.mapper.DrMillProcessPassMapper;
+import com.klp.mapper.DrMillProductionPlanMapper;
+import com.klp.service.IDrMillProductionPlanService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@DS("double-rack")
+@RequiredArgsConstructor
+@Service
+public class DrMillProductionPlanServiceImpl implements IDrMillProductionPlanService {
+
+ private final DrMillProductionPlanMapper planMapper;
+ private final DrMillProcessPassMapper passMapper;
+
+ @Override
+ public List selectList(DrMillProductionPlan query) {
+ return planMapper.selectList(query);
+ }
+
+ @Override
+ public TableDataInfo selectPageList(DrMillProductionPlan query) {
+ if (query.getPageNum() == null || query.getPageNum() < 1) query.setPageNum(1);
+ if (query.getPageSize() == null || query.getPageSize() < 1) query.setPageSize(50);
+ long total = planMapper.countPageList(query);
+ List rows = planMapper.selectPageList(query);
+ TableDataInfo data = TableDataInfo.build(rows);
+ data.setTotal(total);
+ return data;
+ }
+
+ @Override
+ public DrMillProductionPlan selectById(Long id) {
+ return planMapper.selectById(id);
+ }
+
+ @Override
+ public DrMillProductionPlan selectByActionId(Long actionId) {
+ String planNo = "DR" + actionId;
+ DrMillProductionPlan plan = planMapper.selectByPlanNo(planNo);
+ if (plan != null && plan.getRecipeId() != null) {
+ plan.setPassList(passMapper.selectByRecipeId(plan.getRecipeId()));
+ }
+ return plan;
+ }
+
+ @Override
+ public int insert(DrMillProductionPlan plan) {
+ String user = LoginHelper.getUsername();
+ plan.setCreateBy(user);
+ plan.setUpdateBy(user);
+ List all = planMapper.selectList(new DrMillProductionPlan());
+ plan.setSortNo(all.size() + 1);
+ if (plan.getPlanNo() == null || plan.getPlanNo().isEmpty()) {
+ plan.setPlanNo("DR" + System.currentTimeMillis());
+ }
+ return planMapper.insert(plan);
+ }
+
+ @Override
+ public int update(DrMillProductionPlan plan) {
+ plan.setUpdateBy(LoginHelper.getUsername());
+ return planMapper.update(plan);
+ }
+
+ @Override
+ public int deleteById(Long id) {
+ return planMapper.deleteById(id);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int moveUp(Long id) {
+ DrMillProductionPlan cur = planMapper.selectById(id);
+ if (cur == null || cur.getSortNo() <= 1) return 0;
+ List all = planMapper.selectList(new DrMillProductionPlan());
+ DrMillProductionPlan prev = all.stream()
+ .filter(p -> p.getSortNo() == cur.getSortNo() - 1)
+ .findFirst().orElse(null);
+ if (prev == null) return 0;
+ planMapper.updateSortNo(cur.getPlanId(), prev.getSortNo());
+ planMapper.updateSortNo(prev.getPlanId(), cur.getSortNo());
+ return 1;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int moveDown(Long id) {
+ DrMillProductionPlan cur = planMapper.selectById(id);
+ if (cur == null) return 0;
+ List all = planMapper.selectList(new DrMillProductionPlan());
+ DrMillProductionPlan next = all.stream()
+ .filter(p -> p.getSortNo() == cur.getSortNo() + 1)
+ .findFirst().orElse(null);
+ if (next == null) return 0;
+ planMapper.updateSortNo(cur.getPlanId(), next.getSortNo());
+ planMapper.updateSortNo(next.getPlanId(), cur.getSortNo());
+ return 1;
+ }
+
+ @Override
+ public int finish(Long id) {
+ DrMillProductionPlan plan = planMapper.selectById(id);
+ if (plan == null) return 0;
+ plan.setUpdateBy(LoginHelper.getUsername());
+ plan.setPlanStatus("2");
+ plan.setProdStatus("Done");
+ return planMapper.update(plan);
+ }
+}
diff --git a/klp-wms/src/main/java/com/klp/service/impl/DrRecipeSyncService.java b/klp-wms/src/main/java/com/klp/service/impl/DrRecipeSyncService.java
new file mode 100644
index 00000000..e61e5543
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/service/impl/DrRecipeSyncService.java
@@ -0,0 +1,96 @@
+package com.klp.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.klp.domain.DrMillProcessRecipe;
+import com.klp.domain.WmsProcessSpec;
+import com.klp.domain.WmsProductionLine;
+import com.klp.mapper.WmsProcessSpecMapper;
+import com.klp.mapper.WmsProductionLineMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 双机架工艺方案 → L3规程(wms_process_spec)同步服务
+ *
+ * 注意:此 Service 不标注 @DS,默认走 master 数据源,
+ * 供 Controller 在 double-rack 查询完方案列表后调用,
+ * 将缺失的 wms_process_spec 记录自动补齐。
+ *
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class DrRecipeSyncService {
+
+ /** 双机架产线编号,与 wms_production_line.line_code 对应 */
+ private static final String DR_LINE_CODE = "DR";
+ private static final String DR_LINE_NAME = "双机架轧机";
+
+ /** spec_code 前缀,区分同名方案号属于哪条产线 */
+ private static final String SPEC_CODE_PREFIX = "DR-";
+
+ private final WmsProcessSpecMapper specMapper;
+ private final WmsProductionLineMapper lineMapper;
+
+ /**
+ * 检查并补充 wms_process_spec:
+ * 对列表中每条方案,若在 L3 规程表中不存在则自动新增。
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public void syncRecipesToSpec(List recipes) {
+ if (recipes == null || recipes.isEmpty()) return;
+
+ Long lineId = getOrCreateDrLineId();
+
+ int created = 0;
+ for (DrMillProcessRecipe recipe : recipes) {
+ String specCode = SPEC_CODE_PREFIX + recipe.getRecipeNo();
+ LambdaQueryWrapper qw = Wrappers.lambdaQuery();
+ qw.eq(WmsProcessSpec::getSpecCode, specCode);
+ if (specMapper.selectCount(qw) == 0) {
+ WmsProcessSpec spec = new WmsProcessSpec();
+ spec.setSpecCode(specCode);
+ spec.setSpecName(recipe.getRecipeNo());
+ spec.setSpecType("PROCESS");
+ spec.setLineId(lineId);
+ spec.setIsEnabled(1);
+ spec.setRemark("由双机架工艺方案自动同步");
+ specMapper.insert(spec);
+ created++;
+ log.info("[DR同步] 新增 wms_process_spec: specCode={}, recipeId={}",
+ specCode, recipe.getRecipeId());
+ }
+ }
+ if (created > 0) {
+ log.info("[DR同步] 本次共补充 {} 条 L3 工艺规程", created);
+ }
+ }
+
+ /**
+ * 查找或创建双机架产线记录,返回 line_id。
+ */
+ private Long getOrCreateDrLineId() {
+ LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
+ lqw.eq(WmsProductionLine::getLineCode, DR_LINE_CODE);
+ WmsProductionLine line = lineMapper.selectOne(lqw);
+ if (line == null) {
+ line = new WmsProductionLine();
+ line.setLineCode(DR_LINE_CODE);
+ line.setLineName(DR_LINE_NAME);
+ line.setCapacity(BigDecimal.ZERO);
+ line.setUnit("t");
+ line.setIsEnabled(1);
+ line.setRemark("双机架轧机产线,系统自动创建");
+ lineMapper.insert(line);
+ log.info("[DR同步] 新建 wms_production_line: lineCode={}, lineId={}",
+ DR_LINE_CODE, line.getLineId());
+ }
+ return line.getLineId();
+ }
+}
diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsCoilPendingActionServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsCoilPendingActionServiceImpl.java
index a58e1c2c..5a976247 100644
--- a/klp-wms/src/main/java/com/klp/service/impl/WmsCoilPendingActionServiceImpl.java
+++ b/klp-wms/src/main/java/com/klp/service/impl/WmsCoilPendingActionServiceImpl.java
@@ -19,8 +19,12 @@ import com.klp.domain.vo.TheoryCycleRegressionResultVo;
import com.klp.domain.vo.TheoryCycleRegressionVo;
import com.klp.domain.vo.WmsCoilPendingActionVo;
import com.klp.domain.vo.WmsCoilPendingActionIdCoilVo;
+import com.klp.domain.DrMillProductionPlan;
+import com.klp.domain.WmsRawMaterial;
+import com.klp.mapper.DrMillProductionPlanMapper;
import com.klp.mapper.WmsCoilPendingActionMapper;
import com.klp.mapper.WmsMaterialCoilMapper;
+import com.klp.mapper.WmsRawMaterialMapper;
import com.klp.service.IWmsCoilPendingActionService;
import com.klp.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
@@ -52,8 +56,14 @@ public class WmsCoilPendingActionServiceImpl implements IWmsCoilPendingActionSer
private final ISysUserService userService;
private final WmsMaterialCoilMapper materialCoilMapper;
+ private final WmsRawMaterialMapper rawMaterialMapper;
+ private final DrMillProductionPlanMapper drPlanMapper;
private final StringRedisTemplate stringRedisTemplate;
+ /** 双机架工序 / 修复的 actionType */
+ private static final int ACTION_TYPE_DR_NORMAL = 504;
+ private static final int ACTION_TYPE_DR_REPAIR = 524;
+
private static final String REDIS_KEY_IDEAL_CYCLE = "oee:ideal-cycle-time";
/**
@@ -256,10 +266,99 @@ public class WmsCoilPendingActionServiceImpl implements IWmsCoilPendingActionSer
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setActionId(add.getActionId());
+ // 双机架工序/修复:同步在 double-rack 数据库创建生产计划
+ if (ACTION_TYPE_DR_NORMAL == add.getActionType() || ACTION_TYPE_DR_REPAIR == add.getActionType()) {
+ autoCreateDrPlan(add);
+ }
}
return flag;
}
+ /**
+ * 自动创建双机架生产计划(写入 double-rack 数据源)。
+ * 同时查询钢卷库(wms_material_coil)和原材料库(wms_raw_material),
+ * 将完整的钢卷/原料规格信息写入计划。
+ * planNo = "DR" + actionId,保证唯一且可追溯。
+ */
+ @com.baomidou.dynamic.datasource.annotation.DS("double-rack")
+ private void autoCreateDrPlan(WmsCoilPendingAction action) {
+ try {
+ DrMillProductionPlan plan = new DrMillProductionPlan();
+ plan.setPlanNo("DR" + action.getActionId());
+
+ if (action.getCoilId() != null) {
+ // ① 查钢卷库
+ WmsMaterialCoil coil = materialCoilMapper.selectById(action.getCoilId());
+ if (coil != null) {
+ plan.setInMatNo(coil.getEnterCoilNo() != null ? coil.getEnterCoilNo() : coil.getCurrentCoilNo());
+ plan.setEnterCoilNo(coil.getEnterCoilNo());
+ plan.setCurrentCoilNo(coil.getCurrentCoilNo());
+
+ // 实测厚度(优先)
+ if (coil.getActualThickness() != null) {
+ try { plan.setInMatThick(new java.math.BigDecimal(coil.getActualThickness())); } catch (Exception ignored) {}
+ }
+ // 实测宽度(优先)
+ plan.setInMatWidth(coil.getActualWidth());
+ // 净重 > 毛重
+ plan.setInMatWeight(coil.getNetWeight() != null ? coil.getNetWeight() : coil.getGrossWeight());
+ // 长度
+ plan.setInMatLength(coil.getLength());
+
+ // ② 查原材料库(itemType='raw_material' 时通过 itemId 关联)
+ if ("raw_material".equals(coil.getItemType()) && coil.getItemId() != null) {
+ WmsRawMaterial rm = rawMaterialMapper.selectById(coil.getItemId());
+ if (rm != null) {
+ // 钢种/合金号
+ plan.setAlloyNo(rm.getSteelGrade());
+ // 标称厚度(实测没有时用标称补齐)
+ if (plan.getInMatThick() == null && rm.getThickness() != null) {
+ plan.setInMatThick(rm.getThickness());
+ }
+ // 标称宽度(实测没有时用标称补齐)
+ if (plan.getInMatWidth() == null && rm.getWidth() != null) {
+ plan.setInMatWidth(rm.getWidth());
+ }
+ // 卷重(WMS 净重没有时用原材料卷重补齐)
+ if (plan.getInMatWeight() == null && rm.getCoilWeight() != null) {
+ plan.setInMatWeight(rm.getCoilWeight());
+ }
+ // 目标冷轧厚度 / 宽度写入出口目标厚度
+ if (rm.getTargetColdThickness() != null) {
+ plan.setOutThick(rm.getTargetColdThickness());
+ }
+ }
+ }
+ }
+ } else if (action.getCurrentCoilNo() != null) {
+ plan.setInMatNo(action.getCurrentCoilNo());
+ plan.setCurrentCoilNo(action.getCurrentCoilNo());
+ }
+
+ // 修复工序在备注中标记
+ if (ACTION_TYPE_DR_REPAIR == action.getActionType()) {
+ plan.setRemark("[修复] " + (action.getRemark() != null ? action.getRemark() : ""));
+ } else {
+ plan.setRemark(action.getRemark());
+ }
+
+ String user = LoginHelper.getUsername();
+ plan.setCreateBy(user);
+ plan.setUpdateBy(user);
+ plan.setPlanStatus("0");
+ plan.setProdStatus("Idle");
+
+ // 排到队列末尾
+ List all = drPlanMapper.selectList(new DrMillProductionPlan());
+ plan.setSortNo(all.size() + 1);
+
+ drPlanMapper.insert(plan);
+ } catch (Exception e) {
+ org.slf4j.LoggerFactory.getLogger(getClass())
+ .error("[双机架] 自动创建生产计划失败, actionId={}", action.getActionId(), e);
+ }
+ }
+
/**
* 修改钢卷待操作
*/
diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsMaterialCoilServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsMaterialCoilServiceImpl.java
index 2fa05f60..d3734ce0 100644
--- a/klp-wms/src/main/java/com/klp/service/impl/WmsMaterialCoilServiceImpl.java
+++ b/klp-wms/src/main/java/com/klp/service/impl/WmsMaterialCoilServiceImpl.java
@@ -1356,12 +1356,12 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
}
result = updateBySingle(bo, qrcodeStepType); // 返回新钢卷ID字符串
}
-
+
// 如果有关联的操作记录ID,调用完成接口
if (bo.getActionId() != null && bo.getActionId() > 0) {
coilPendingActionService.completeAction(bo.getActionId(), result);
}
-
+
return result;
}
@@ -5743,5 +5743,15 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
return baseMapper.update(null, updateWrapper) > 0;
}
+ @Override
+ public WmsMaterialCoilVo queryByCoilNo(String coilNo) {
+ LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
+ lqw.eq(WmsMaterialCoil::getEnterCoilNo, coilNo)
+ .or()
+ .eq(WmsMaterialCoil::getCurrentCoilNo, coilNo);
+ lqw.last("LIMIT 1");
+ return baseMapper.selectVoOne(lqw);
+ }
+
}
diff --git a/klp-wms/src/main/java/com/klp/task/DrMigrationRunner.java b/klp-wms/src/main/java/com/klp/task/DrMigrationRunner.java
new file mode 100644
index 00000000..bef49bd8
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/task/DrMigrationRunner.java
@@ -0,0 +1,33 @@
+package com.klp.task;
+
+import com.klp.service.impl.DrMigrationService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ * 应用启动后自动执行双机架历史道次版本迁移。
+ * 逻辑幂等:若已迁移完毕则无任何 DB 写操作,仅打印一条 info 日志。
+ */
+@Slf4j
+@Order(100)
+@Component
+@RequiredArgsConstructor
+public class DrMigrationRunner implements ApplicationRunner {
+
+ private final DrMigrationService migrationService;
+
+ @Override
+ public void run(ApplicationArguments args) {
+ log.info("[DR迁移] 开始检查历史道次版本迁移...");
+ try {
+ migrationService.migrateOrphanPassesToV1();
+ } catch (Exception e) {
+ // 迁移失败不阻断服务启动,只记录错误
+ log.error("[DR迁移] 执行异常,请人工检查 mill_process_pass 表", e);
+ }
+ }
+}
diff --git a/klp-wms/src/main/resources/mapper/DrMillProcessPassMapper.xml b/klp-wms/src/main/resources/mapper/DrMillProcessPassMapper.xml
new file mode 100644
index 00000000..e249ca77
--- /dev/null
+++ b/klp-wms/src/main/resources/mapper/DrMillProcessPassMapper.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO mill_process_pass (
+ recipe_id, version_id, pass_no, in_thick, out_thick, width,
+ roll_force, in_tension, out_tension, max_speed,
+ in_unit_tension, out_unit_tension, reduction, total_reduction,
+ create_by, create_time, update_by, update_time, remark, del_flag
+ ) VALUES
+
+ (#{p.recipeId}, #{p.versionId}, #{p.passNo}, #{p.inThick}, #{p.outThick}, #{p.width},
+ #{p.rollForce}, #{p.inTension}, #{p.outTension}, #{p.maxSpeed},
+ #{p.inUnitTension}, #{p.outUnitTension}, #{p.reduction}, #{p.totalReduction},
+ #{p.createBy}, NOW(), #{p.updateBy}, NOW(), #{p.remark}, '0')
+
+
+
+
+ UPDATE mill_process_pass SET del_flag = '2', update_time = NOW()
+ WHERE version_id = #{versionId}
+
+
+
+ UPDATE mill_process_pass SET del_flag = '2', update_time = NOW()
+ WHERE recipe_id = #{recipeId}
+
+
+
+
+
+ UPDATE mill_process_pass
+ SET version_id = #{versionId},
+ update_time = NOW()
+ WHERE recipe_id = #{recipeId}
+ AND version_id IS NULL
+ AND del_flag = '0'
+
+
+
diff --git a/klp-wms/src/main/resources/mapper/DrMillProcessRecipeMapper.xml b/klp-wms/src/main/resources/mapper/DrMillProcessRecipeMapper.xml
new file mode 100644
index 00000000..a59182f9
--- /dev/null
+++ b/klp-wms/src/main/resources/mapper/DrMillProcessRecipeMapper.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ recipe_id, recipe_no, alloy_no, pass_count, in_thick, out_thick, out_width,
+ status, del_flag, create_by, create_time, update_by, update_time, remark
+
+
+
+
+
+
+
+ INSERT INTO mill_process_recipe (
+ recipe_no, alloy_no, pass_count, in_thick, out_thick, out_width,
+ status, create_by, create_time, update_by, update_time, remark, del_flag
+ ) VALUES (
+ #{recipeNo}, #{alloyNo}, #{passCount}, #{inThick}, #{outThick}, #{outWidth},
+ #{status}, #{createBy}, NOW(), #{updateBy}, NOW(), #{remark}, '0'
+ )
+
+
+
+ UPDATE mill_process_recipe
+ SET recipe_no = #{recipeNo},
+ alloy_no = #{alloyNo},
+ pass_count = #{passCount},
+ in_thick = #{inThick},
+ out_thick = #{outThick},
+ out_width = #{outWidth},
+ status = #{status},
+ update_by = #{updateBy},
+ update_time = NOW(),
+ remark = #{remark}
+ WHERE recipe_id = #{recipeId}
+
+
+
+ UPDATE mill_process_recipe SET del_flag = '2', update_time = NOW()
+ WHERE recipe_id IN
+ #{id}
+
+
+
diff --git a/klp-wms/src/main/resources/mapper/DrMillProcessRecipeVersionMapper.xml b/klp-wms/src/main/resources/mapper/DrMillProcessRecipeVersionMapper.xml
new file mode 100644
index 00000000..575d4991
--- /dev/null
+++ b/klp-wms/src/main/resources/mapper/DrMillProcessRecipeVersionMapper.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ version_id, recipe_id, version_code, is_active, status,
+ create_by, create_time, update_by, update_time, remark, del_flag
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO mill_process_recipe_version (
+ recipe_id, version_code, is_active, status,
+ create_by, create_time, update_by, update_time, remark, del_flag
+ ) VALUES (
+ #{recipeId}, #{versionCode}, IFNULL(#{isActive}, 0), IFNULL(#{status}, '0'),
+ #{createBy}, NOW(), #{updateBy}, NOW(), #{remark}, '0'
+ )
+
+
+
+ UPDATE mill_process_recipe_version
+ SET version_code = #{versionCode},
+ status = #{status},
+ update_by = #{updateBy},
+ update_time = NOW(),
+ remark = #{remark}
+ WHERE version_id = #{versionId}
+
+
+
+ UPDATE mill_process_recipe_version SET del_flag = '2', update_time = NOW()
+ WHERE version_id = #{versionId}
+
+
+
+ UPDATE mill_process_recipe_version SET del_flag = '2', update_time = NOW()
+ WHERE recipe_id IN
+ #{id}
+
+
+
+ UPDATE mill_process_recipe_version
+ SET is_active = 0, update_time = NOW()
+ WHERE recipe_id = #{recipeId} AND version_id != #{versionId} AND del_flag = '0'
+
+
+
+ UPDATE mill_process_recipe_version
+ SET is_active = 1, status = '1', update_time = NOW()
+ WHERE version_id = #{versionId}
+
+
+
diff --git a/klp-wms/src/main/resources/mapper/DrMillProductionPlanMapper.xml b/klp-wms/src/main/resources/mapper/DrMillProductionPlanMapper.xml
new file mode 100644
index 00000000..c1eea7ba
--- /dev/null
+++ b/klp-wms/src/main/resources/mapper/DrMillProductionPlanMapper.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ plan_id, plan_no, plan_status, prod_status, sort_no,
+ in_mat_no, sg_sign, in_mat_thick, in_mat_width, in_mat_wt, in_mat_len,
+ in_mat_in_dia, in_mat_dia, out_thick, pass_count, recipe_id, recipe_no,
+ version_id, enter_coil_no, current_coil_no,
+ del_flag, create_by, create_time, update_by, update_time, remark
+
+
+
+
+
+
+ WHERE del_flag = '0'
+
+ AND (in_mat_no LIKE CONCAT('%',#{inMatNo},'%')
+ OR enter_coil_no LIKE CONCAT('%',#{inMatNo},'%')
+ OR current_coil_no LIKE CONCAT('%',#{inMatNo},'%'))
+
+
+ AND plan_status = #{planStatus}
+
+
+ AND create_time >= #{createStartTime}
+
+
+ AND create_time <= #{createEndTime}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO mill_production_plan (
+ plan_no, plan_status, prod_status, sort_no,
+ in_mat_no, sg_sign, in_mat_thick, in_mat_width, in_mat_wt, in_mat_len,
+ in_mat_in_dia, in_mat_dia, out_thick, pass_count, recipe_id, recipe_no,
+ version_id, enter_coil_no, current_coil_no,
+ create_by, create_time, update_by, update_time, remark, del_flag
+ ) VALUES (
+ #{planNo}, IFNULL(#{planStatus},'0'), IFNULL(#{prodStatus},'Idle'), IFNULL(#{sortNo},0),
+ #{inMatNo}, #{alloyNo}, #{inMatThick}, #{inMatWidth}, #{inMatWeight}, #{inMatLength},
+ #{inMatId}, #{inMatOd}, #{outThick}, IFNULL(#{passCount},0), #{recipeId}, #{recipeNo},
+ #{versionId}, #{enterCoilNo}, #{currentCoilNo},
+ #{createBy}, NOW(), #{updateBy}, NOW(), #{remark}, '0'
+ )
+
+
+
+ UPDATE mill_production_plan
+ SET plan_status = #{planStatus},
+ prod_status = #{prodStatus},
+ in_mat_no = #{inMatNo},
+ sg_sign = #{alloyNo},
+ in_mat_thick = #{inMatThick},
+ in_mat_width = #{inMatWidth},
+ in_mat_wt = #{inMatWeight},
+ in_mat_len = #{inMatLength},
+ in_mat_in_dia = #{inMatId},
+ in_mat_dia = #{inMatOd},
+ out_thick = #{outThick},
+ pass_count = #{passCount},
+ recipe_id = #{recipeId},
+ recipe_no = #{recipeNo},
+ version_id = #{versionId},
+ enter_coil_no = #{enterCoilNo},
+ current_coil_no = #{currentCoilNo},
+ update_by = #{updateBy},
+ update_time = NOW(),
+ remark = #{remark}
+ WHERE plan_id = #{planId}
+
+
+
+ UPDATE mill_production_plan SET del_flag = '2', update_time = NOW()
+ WHERE plan_id = #{planId}
+
+
+
+ UPDATE mill_production_plan SET sort_no = #{sortNo} WHERE plan_id = #{planId}
+
+
+