Merge remote-tracking branch 'origin/0.8.X' into 0.8.X
This commit is contained in:
81
docs/double-rack-ddl.sql
Normal file
81
docs/double-rack-ddl.sql
Normal file
@@ -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='双机架生产计划表(轧制队列)';
|
||||
@@ -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
|
||||
# 连接空闲超时,单位:毫秒
|
||||
|
||||
@@ -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
|
||||
|
||||
100
klp-ui/src/api/wms/drMill.js
Normal file
100
klp-ui/src/api/wms/drMill.js
Normal file
@@ -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 }
|
||||
@@ -142,7 +142,7 @@
|
||||
</div>
|
||||
|
||||
<div class="selected-table-wrapper">
|
||||
<el-table :data="selectedCoils" :height="orderBy ? '100%' : '200px'">
|
||||
<el-table :data="selectedCoils" :height="orderBy ? 'calc(100% - 30px)' : '200px'">
|
||||
<el-table-column v-for="column in renderColumns" :label="column.label" :align="column.align"
|
||||
:prop="column.prop" :width="column.width" :show-overflow-tooltip="column.showOverflowTooltip" />
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,6 +253,7 @@ export default {
|
||||
cursor: pointer;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
white-space: nowrap;
|
||||
border: 1px solid #a0a6ad;
|
||||
color: #111;
|
||||
// 标签金属渐变背景
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
<template>
|
||||
<div class="acid-container">
|
||||
<div class="acid-sidebar">
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
class="sidebar-menu"
|
||||
@select="handleMenuSelect"
|
||||
>
|
||||
<el-menu :default-active="activeMenu" class="sidebar-menu" @select="handleMenuSelect">
|
||||
<el-menu-item index="inventory">
|
||||
<i class="el-icon-box"></i>
|
||||
<span slot="title">库存</span>
|
||||
@@ -34,6 +30,10 @@
|
||||
<i class="el-icon-date"></i>
|
||||
<span slot="title">计划</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="tracking">
|
||||
<i class="el-icon-location-outline"></i>
|
||||
<span slot="title">跟踪</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="actualPerformance">
|
||||
<i class="el-icon-data-analysis"></i>
|
||||
<span slot="title">实绩</span>
|
||||
@@ -54,10 +54,6 @@
|
||||
<i class="el-icon-alarm-clock"></i>
|
||||
<span slot="title">app</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="tracking">
|
||||
<i class="el-icon-location-outline"></i>
|
||||
<span slot="title">跟踪</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</div>
|
||||
<div style="flex: 1; overflow: hidden;">
|
||||
|
||||
468
klp-ui/src/views/micro/pages/dr/components/Actual.vue
Normal file
468
klp-ui/src/views/micro/pages/dr/components/Actual.vue
Normal file
@@ -0,0 +1,468 @@
|
||||
<template>
|
||||
<div class="actual-page">
|
||||
<div class="body-wrap">
|
||||
|
||||
<!-- 实绩表格 -->
|
||||
<div class="table-card">
|
||||
<div class="card-header">
|
||||
<span class="card-title">双机架实绩</span>
|
||||
<el-radio-group v-model="query.planStatus" size="mini" @change="onStatusChange">
|
||||
<el-radio-button label="">全部</el-radio-button>
|
||||
<el-radio-button label="0">准备</el-radio-button>
|
||||
<el-radio-button label="1">上线</el-radio-button>
|
||||
<el-radio-button label="2">生产中</el-radio-button>
|
||||
<el-radio-button label="3">生产完成</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-button size="mini" icon="el-icon-refresh" style="margin-left:8px" @click="loadList">刷新</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
size="mini"
|
||||
border
|
||||
highlight-current-row
|
||||
:height="tableHeight"
|
||||
style="width:100%"
|
||||
@row-click="handleRowClick"
|
||||
>
|
||||
<el-table-column type="index" width="40" align="center" />
|
||||
<el-table-column label="计划号" prop="planNo" width="150" show-overflow-tooltip />
|
||||
<el-table-column label="入场钢卷号" prop="enterCoilNo" min-width="120" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.enterCoilNo || row.inMatNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口钢卷号" prop="currentCoilNo" min-width="120" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.currentCoilNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="合金牌号" prop="alloyNo" width="100" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.alloyNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="计划状态" width="80" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-tag :type="planStatusType(row.planStatus)" size="mini">
|
||||
{{ planStatusLabel(row.planStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="生产状态" width="80" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-tag :type="prodStatusType(row.prodStatus)" size="mini" effect="plain">
|
||||
{{ row.prodStatus || '—' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来料厚(mm)" width="82" align="right">
|
||||
<template slot-scope="{ row }">{{ row.inMatThick || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来料宽(mm)" width="82" align="right">
|
||||
<template slot-scope="{ row }">{{ row.inMatWidth || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来料重(t)" width="76" align="right">
|
||||
<template slot-scope="{ row }">{{ row.inMatWeight || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成品厚(mm)" width="82" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<span class="accent-val">{{ row.outThick || '—' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="道次数" prop="passCount" width="60" align="center">
|
||||
<template slot-scope="{ row }">{{ row.passCount || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="工艺方案" prop="recipeNo" width="110" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.recipeNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" width="148">
|
||||
<template slot-scope="{ row }">{{ formatDate(row.createTime) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建人" prop="createBy" width="80" align="center">
|
||||
<template slot-scope="{ row }">{{ row.createBy || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" prop="remark" min-width="100" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.remark || '—' }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="table-footer">
|
||||
<el-pagination
|
||||
small
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:page-sizes="[20, 50, 100]"
|
||||
:total="total"
|
||||
:page-size="query.pageSize"
|
||||
:current-page="query.pageNum"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧面板 -->
|
||||
<div class="side-panel">
|
||||
|
||||
<!-- 查找 -->
|
||||
<div class="panel-block">
|
||||
<div class="panel-title">查找</div>
|
||||
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">钢卷号</span>
|
||||
<el-input
|
||||
v-model="query.inMatNo"
|
||||
size="mini" clearable
|
||||
placeholder="入场/出口钢卷号"
|
||||
style="width:100%"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">开始时间</span>
|
||||
<el-date-picker
|
||||
v-model="query.createStartTime"
|
||||
type="datetime"
|
||||
size="mini"
|
||||
style="width:100%"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="创建开始时间"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">结束时间</span>
|
||||
<el-date-picker
|
||||
v-model="query.createEndTime"
|
||||
type="datetime"
|
||||
size="mini"
|
||||
style="width:100%"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="创建结束时间"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="filter-actions">
|
||||
<el-button type="primary" size="mini" :loading="loading" @click="handleSearch">查找</el-button>
|
||||
<el-button size="mini" @click="handleReset">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 选中行详情 -->
|
||||
<div v-if="selectedRow" class="panel-block detail-block">
|
||||
<div class="panel-title">计划详情</div>
|
||||
<div class="detail-grid">
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">计划号</span>
|
||||
<span class="detail-val">{{ selectedRow.planNo }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">入场卷号</span>
|
||||
<span class="detail-val">{{ selectedRow.enterCoilNo || selectedRow.inMatNo || '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">出口卷号</span>
|
||||
<span class="detail-val">{{ selectedRow.currentCoilNo || '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">合金牌号</span>
|
||||
<span class="detail-val">{{ selectedRow.alloyNo || '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">来料厚</span>
|
||||
<span class="detail-val accent">{{ selectedRow.inMatThick ? selectedRow.inMatThick + ' mm' : '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">来料宽</span>
|
||||
<span class="detail-val accent">{{ selectedRow.inMatWidth ? selectedRow.inMatWidth + ' mm' : '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">来料重</span>
|
||||
<span class="detail-val accent">{{ selectedRow.inMatWeight ? selectedRow.inMatWeight + ' t' : '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">来料长</span>
|
||||
<span class="detail-val">{{ selectedRow.inMatLength ? selectedRow.inMatLength + ' m' : '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">成品厚</span>
|
||||
<span class="detail-val accent">{{ selectedRow.outThick ? selectedRow.outThick + ' mm' : '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">道次数</span>
|
||||
<span class="detail-val">{{ selectedRow.passCount || '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">工艺方案</span>
|
||||
<span class="detail-val">{{ selectedRow.recipeNo || '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">计划状态</span>
|
||||
<span class="detail-val">
|
||||
<el-tag :type="planStatusType(selectedRow.planStatus)" size="mini">
|
||||
{{ planStatusLabel(selectedRow.planStatus) }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">生产状态</span>
|
||||
<span class="detail-val">
|
||||
<el-tag :type="prodStatusType(selectedRow.prodStatus)" size="mini" effect="plain">
|
||||
{{ selectedRow.prodStatus || '—' }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">创建人</span>
|
||||
<span class="detail-val">{{ selectedRow.createBy || '—' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-key">创建时间</span>
|
||||
<span class="detail-val">{{ formatDate(selectedRow.createTime) }}</span>
|
||||
</div>
|
||||
<div v-if="selectedRow.remark" class="detail-row">
|
||||
<span class="detail-key">备注</span>
|
||||
<span class="detail-val">{{ selectedRow.remark }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listDrActualPage } from '@/api/wms/drMill'
|
||||
|
||||
const PLAN_STATUS = {
|
||||
'0': { label: '准备', type: 'info' },
|
||||
'1': { label: '上线', type: 'primary' },
|
||||
'2': { label: '生产中', type: 'warning' },
|
||||
'3': { label: '生产完成', type: 'success' },
|
||||
}
|
||||
|
||||
const PROD_STATUS_TYPE = {
|
||||
Idle: 'info',
|
||||
Rolling: 'warning',
|
||||
NextCoil: 'primary',
|
||||
Done: 'success',
|
||||
Error: 'danger',
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'DrActual',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
list: [],
|
||||
total: 0,
|
||||
selectedRow: null,
|
||||
query: {
|
||||
pageNum: 1,
|
||||
pageSize: 50,
|
||||
planStatus: '',
|
||||
inMatNo: '',
|
||||
createStartTime: '',
|
||||
createEndTime: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tableHeight() { return 'calc(100vh - 210px)' }
|
||||
},
|
||||
created() { this.loadList() },
|
||||
methods: {
|
||||
loadList() {
|
||||
this.loading = true
|
||||
const params = {
|
||||
...this.query,
|
||||
planStatus: this.query.planStatus || undefined,
|
||||
inMatNo: this.query.inMatNo || undefined,
|
||||
createStartTime: this.query.createStartTime || undefined,
|
||||
createEndTime: this.query.createEndTime || undefined,
|
||||
}
|
||||
listDrActualPage(params)
|
||||
.then(res => {
|
||||
this.list = res.rows || []
|
||||
this.total = res.total || 0
|
||||
})
|
||||
.finally(() => { this.loading = false })
|
||||
},
|
||||
handlePageChange(page) {
|
||||
this.query.pageNum = page
|
||||
this.loadList()
|
||||
},
|
||||
handleSizeChange(size) {
|
||||
this.query.pageSize = size
|
||||
this.query.pageNum = 1
|
||||
this.loadList()
|
||||
},
|
||||
onStatusChange() {
|
||||
this.query.pageNum = 1
|
||||
this.loadList()
|
||||
},
|
||||
handleRowClick(row) {
|
||||
this.selectedRow = (this.selectedRow && this.selectedRow.planId === row.planId) ? null : row
|
||||
},
|
||||
handleSearch() {
|
||||
this.query.pageNum = 1
|
||||
this.loadList()
|
||||
},
|
||||
handleReset() {
|
||||
this.query.planStatus = ''
|
||||
this.query.inMatNo = ''
|
||||
this.query.createStartTime = ''
|
||||
this.query.createEndTime = ''
|
||||
this.query.pageNum = 1
|
||||
this.selectedRow = null
|
||||
this.loadList()
|
||||
},
|
||||
planStatusLabel(s) { return (PLAN_STATUS[s] || { label: s || '—' }).label },
|
||||
planStatusType(s) { return (PLAN_STATUS[s] || { type: '' }).type },
|
||||
prodStatusType(s) { return PROD_STATUS_TYPE[s] || 'info' },
|
||||
formatDate(v) {
|
||||
if (!v) return '—'
|
||||
return String(v).replace('T', ' ').substring(0, 19)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.actual-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background: #f5f7fa;
|
||||
padding: 10px 12px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.body-wrap {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── 表格卡片 ── */
|
||||
.table-card {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 14px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
flex-shrink: 0;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.table-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 6px 10px;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
background: #fafafa;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.accent-val {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-weight: 600;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
/* ── 侧边面板 ── */
|
||||
.side-panel {
|
||||
width: 220px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar { width: 4px; }
|
||||
&::-webkit-scrollbar-thumb { background: #dcdfe6; border-radius: 2px; }
|
||||
}
|
||||
|
||||
.panel-block {
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.filter-item { margin-bottom: 10px; }
|
||||
|
||||
.filter-label {
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
color: #909399;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.filter-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* ── 详情 ── */
|
||||
.detail-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.detail-key {
|
||||
font-size: 11px;
|
||||
color: #909399;
|
||||
flex-shrink: 0;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.detail-val {
|
||||
font-size: 12px;
|
||||
color: #303133;
|
||||
text-align: right;
|
||||
word-break: break-all;
|
||||
|
||||
&.accent {
|
||||
color: #409eff;
|
||||
font-weight: 600;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
516
klp-ui/src/views/micro/pages/dr/components/Plan.vue
Normal file
516
klp-ui/src/views/micro/pages/dr/components/Plan.vue
Normal file
@@ -0,0 +1,516 @@
|
||||
<template>
|
||||
<div class="plan-page">
|
||||
|
||||
<!-- 上方:轧制队列 -->
|
||||
<div class="queue-section">
|
||||
<div class="section-header"><span>双机架轧制队列</span></div>
|
||||
<el-table :data="planList" border size="mini" class="queue-table"
|
||||
:row-class-name="queueRowClass"
|
||||
@current-change="handleQueueSelect"
|
||||
highlight-current-row
|
||||
height="240">
|
||||
<el-table-column label="序号" prop="sortNo" width="50" align="center" fixed />
|
||||
<el-table-column label="入场钢卷号" prop="enterCoilNo" width="115" />
|
||||
<el-table-column label="当前钢卷号" prop="currentCoilNo" width="115" />
|
||||
<el-table-column label="钢卷编号" prop="inMatNo" width="110" />
|
||||
<el-table-column label="合金牌号" prop="alloyNo" width="90" />
|
||||
<el-table-column label="采料厚度(mm)" prop="inMatThick" width="105" align="right" />
|
||||
<el-table-column label="成品厚度(mm)" prop="outThick" width="105" align="right" />
|
||||
<el-table-column label="采料宽度(mm)" prop="inMatWidth" width="105" align="right" />
|
||||
<el-table-column label="采料重量(t)" prop="inMatWeight" width="100" align="right" />
|
||||
<el-table-column label="道次数" prop="passCount" width="65" align="center" />
|
||||
<el-table-column label="生产状态" prop="prodStatus" width="85" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span :class="prodStatusClass(row.prodStatus)">{{ prodStatusLabel(row.prodStatus) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="工艺方案" prop="recipeNo" min-width="100" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 下方 -->
|
||||
<div class="bottom-section">
|
||||
|
||||
<!-- 左侧:绑定工艺 -->
|
||||
<div class="pass-panel">
|
||||
<template v-if="!selectedPlan">
|
||||
<div class="section-header"><span>轧制工艺</span></div>
|
||||
<div class="pass-empty">请在上方选择一条计划</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="selectedPlan.recipeId && !passEditMode">
|
||||
<div class="section-header">
|
||||
<span>轧制工艺</span>
|
||||
<div style="display:flex;align-items:center;gap:8px">
|
||||
<span class="recipe-tag">{{ selectedPlan.recipeNo }}</span>
|
||||
<span v-if="boundVersionCode" class="recipe-tag" style="color:#409eff;background:#ecf5ff">
|
||||
{{ boundVersionCode }}
|
||||
</span>
|
||||
<el-button size="mini" icon="el-icon-edit" @click="enterEditMode">修改绑定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="passList" border size="mini" class="pass-table"
|
||||
:row-class-name="passRowClass" height="300">
|
||||
<el-table-column label="道次" prop="passNo" width="45" align="center" fixed />
|
||||
<el-table-column label="入口厚(mm)" prop="inThick" width="90" align="right" />
|
||||
<el-table-column label="出口厚(mm)" prop="outThick" width="90" align="right" />
|
||||
<el-table-column label="轧制力(kN)" prop="rollForce" width="85" align="right" />
|
||||
<el-table-column label="入口张力(kN)" prop="inTension" width="90" align="right" />
|
||||
<el-table-column label="出口张力(kN)" prop="outTension" width="90" align="right" />
|
||||
<el-table-column label="最高速度" prop="maxSpeed" width="80" align="right" />
|
||||
<el-table-column label="压下量(mm)" prop="reduction" width="85" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.reduction }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总压下量(mm)" prop="totalReduction" width="100" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.totalReduction }}</span></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<template v-else-if="!selectedPlan.recipeId && !passEditMode">
|
||||
<div class="section-header"><span>轧制工艺</span></div>
|
||||
<div class="pass-empty">
|
||||
<span>该计划尚未绑定工艺参数</span>
|
||||
<div style="margin-top:12px">
|
||||
<el-button size="mini" type="primary" icon="el-icon-document-copy" @click="openSelectRecipe">选择已有方案</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:查询 + 操作 -->
|
||||
<div class="op-panel">
|
||||
<div class="section-header"><span>条件查询</span></div>
|
||||
<div class="query-form">
|
||||
<el-form size="mini" label-width="72px">
|
||||
<el-form-item label="钢卷号">
|
||||
<el-input v-model="query.inMatNo" clearable placeholder="入场/当前钢卷号" />
|
||||
</el-form-item>
|
||||
<el-form-item label=" " label-width="72px">
|
||||
<el-checkbox v-model="query.hideFinished">不显示已完成</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item label=" " label-width="72px">
|
||||
<el-button size="mini" type="primary" icon="el-icon-search" @click="loadList">查询</el-button>
|
||||
<el-button size="mini" icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="section-header" style="margin-top:8px"><span>队列操作</span></div>
|
||||
<div class="op-buttons">
|
||||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="handleAdd">新增计划</el-button>
|
||||
<el-button size="mini" icon="el-icon-edit" :disabled="!selectedPlan" @click="handleEdit">修改</el-button>
|
||||
<el-button size="mini" icon="el-icon-document" :disabled="!selectedPlan" @click="handleFinish">完成</el-button>
|
||||
<el-button size="mini" type="danger" icon="el-icon-delete" :disabled="!selectedPlan" @click="handleDelete">删除</el-button>
|
||||
<el-button size="mini" icon="el-icon-top" :disabled="!selectedPlan" @click="handleMoveUp">Up 上移</el-button>
|
||||
<el-button size="mini" icon="el-icon-bottom" :disabled="!selectedPlan" @click="handleMoveDown">Down 下移</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增/修改对话框 -->
|
||||
<el-dialog :title="planDialogTitle" :visible.sync="planDialogVisible" width="680px"
|
||||
:close-on-click-modal="false" append-to-body>
|
||||
<el-form :model="form" :rules="rules" ref="formRef" size="mini" label-width="100px">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="入场钢卷号" prop="enterCoilNo">
|
||||
<el-input v-model="form.enterCoilNo"
|
||||
@keyup.enter.native="onCoilNoInput" @blur="onCoilNoInput" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="当前钢卷号">
|
||||
<el-input v-model="form.currentCoilNo" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="合金牌号" prop="alloyNo">
|
||||
<el-input v-model="form.alloyNo" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工艺方案">
|
||||
<el-select v-model="form.recipeId" filterable clearable
|
||||
placeholder="可后续在下方绑定" style="width:100%" @change="onRecipeChange">
|
||||
<el-option v-for="r in recipeOptions" :key="r.recipeId"
|
||||
:label="`${r.recipeNo}(${r.alloyNo})`" :value="r.recipeId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料厚度">
|
||||
<el-input v-model="form.inMatThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="成品厚度">
|
||||
<el-input v-model="form.outThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料宽度">
|
||||
<el-input v-model="form.inMatWidth"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料重量">
|
||||
<el-input v-model="form.inMatWeight"><template slot="append">t</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料长度">
|
||||
<el-input v-model="form.inMatLength"><template slot="append">m</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="planDialogVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="handleSave">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 选择工艺方案 + 版本 -->
|
||||
<el-dialog title="绑定工艺方案" :visible.sync="selectRecipeVisible" width="520px"
|
||||
:close-on-click-modal="false" append-to-body>
|
||||
<el-form size="small" label-width="72px">
|
||||
<el-form-item label="工艺方案">
|
||||
<el-select v-model="selectRecipeId" filterable clearable
|
||||
placeholder="输入方案号或合金号搜索" style="width:100%"
|
||||
@change="onSelectRecipeChange">
|
||||
<el-option v-for="r in recipeOptions" :key="r.recipeId"
|
||||
:label="`${r.recipeNo}(${r.alloyNo})${r.inThick}→${r.outThick}mm`"
|
||||
:value="r.recipeId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="版本">
|
||||
<el-select v-model="selectVersionId" placeholder="请先选择方案" style="width:100%"
|
||||
:disabled="!selectRecipeId || !selectVersionList.length">
|
||||
<el-option v-for="v in selectVersionList" :key="v.versionId"
|
||||
:label="`${v.versionCode}${v.isActive === 1 ? '(当前激活)' : v.status === '1' ? '(已发布)' : '(草稿)'}`"
|
||||
:value="v.versionId" />
|
||||
</el-select>
|
||||
<div v-if="selectRecipeId && !selectVersionList.length" style="font-size:12px;color:#f56c6c;margin-top:4px">
|
||||
该方案暂无版本,请先在「规程」页新增版本
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="selectRecipeVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="confirmSelectRecipe"
|
||||
:disabled="!selectVersionId">确定绑定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listDrPlan, addDrPlan, updateDrPlan, delDrPlan, moveUpDrPlan, moveDownDrPlan, finishDrPlan,
|
||||
listDrRecipe, getDrRecipeDetail,
|
||||
listDrRecipeVersions, getDrRecipeVersionDetail,
|
||||
queryCoilByNo } from '@/api/wms/drMill'
|
||||
|
||||
const emptyForm = () => ({
|
||||
planId: null, planNo: '', enterCoilNo: '', currentCoilNo: '', inMatNo: '',
|
||||
alloyNo: '', recipeId: null, recipeNo: '',
|
||||
outThick: '', inMatThick: '', inMatWidth: '', inMatLength: '',
|
||||
inMatWeight: '', inMatOd: '', inMatId: '', passCount: 0, remark: ''
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'DrPlanTab',
|
||||
data() {
|
||||
return {
|
||||
planList: [],
|
||||
selectedPlan: null,
|
||||
passList: [],
|
||||
recipeOptions: [],
|
||||
query: { inMatNo: '', hideFinished: false },
|
||||
passEditMode: false,
|
||||
planDialogVisible: false,
|
||||
isNew: true,
|
||||
form: emptyForm(),
|
||||
rules: {
|
||||
enterCoilNo: [{ required: true, message: '请输入入场钢卷号', trigger: 'blur' }],
|
||||
alloyNo: [{ required: true, message: '请输入合金牌号', trigger: 'blur' }],
|
||||
},
|
||||
selectRecipeVisible: false,
|
||||
selectRecipeId: null,
|
||||
selectVersionList: [], // 选方案后加载的版本列表
|
||||
selectVersionId: null, // 用户选中的版本ID
|
||||
boundVersionCode: '', // 当前计划绑定的版本号(展示用)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
planDialogTitle() { return this.isNew ? '新增双机架计划' : '修改双机架计划' }
|
||||
},
|
||||
mounted() {
|
||||
this.loadList()
|
||||
this.refreshRecipeOptions()
|
||||
},
|
||||
methods: {
|
||||
refreshRecipeOptions() {
|
||||
listDrRecipe({}).then(res => { this.recipeOptions = res.data || [] })
|
||||
},
|
||||
loadList() {
|
||||
const params = { inMatNo: this.query.inMatNo }
|
||||
if (this.query.hideFinished) params.planStatus = '0'
|
||||
listDrPlan(params).then(res => { this.planList = res.data || [] })
|
||||
},
|
||||
resetQuery() {
|
||||
this.query = { inMatNo: '', hideFinished: false }
|
||||
this.loadList()
|
||||
},
|
||||
handleQueueSelect(row) {
|
||||
this.selectedPlan = row
|
||||
this.passList = []
|
||||
this.boundVersionCode = ''
|
||||
if (!row) return
|
||||
if (row.versionId) {
|
||||
// 优先用版本ID精确加载道次
|
||||
getDrRecipeVersionDetail(row.versionId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
this.boundVersionCode = res.data ? res.data.versionCode : ''
|
||||
})
|
||||
} else if (row.recipeId) {
|
||||
// 兼容旧数据:取激活版本道次(后端 selectDetailById 已处理)
|
||||
getDrRecipeDetail(row.recipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 入场钢卷号变化 → 查 WMS 自动填入
|
||||
onCoilNoInput() {
|
||||
const v = (this.form.enterCoilNo || '').trim()
|
||||
if (!v) return
|
||||
this.form.inMatNo = v
|
||||
queryCoilByNo(v).then(res => {
|
||||
const c = res.data
|
||||
if (!c) return
|
||||
if (c.actualThickness && !this.form.inMatThick) this.form.inMatThick = c.actualThickness
|
||||
if (c.actualWidth && !this.form.inMatWidth) this.form.inMatWidth = String(c.actualWidth)
|
||||
if (c.netWeight && !this.form.inMatWeight) this.form.inMatWeight = String(c.netWeight)
|
||||
if (c.length && !this.form.inMatLength) this.form.inMatLength = String(c.length)
|
||||
if (c.currentCoilNo && !this.form.currentCoilNo) this.form.currentCoilNo = c.currentCoilNo
|
||||
this.$message.success('已从 WMS 自动填入钢卷数据')
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
openSelectRecipe() {
|
||||
this.selectRecipeId = null
|
||||
this.selectVersionId = null
|
||||
this.selectVersionList = []
|
||||
this.selectRecipeVisible = true
|
||||
},
|
||||
onSelectRecipeChange(recipeId) {
|
||||
this.selectVersionId = null
|
||||
this.selectVersionList = []
|
||||
if (!recipeId) return
|
||||
listDrRecipeVersions(recipeId).then(res => {
|
||||
this.selectVersionList = res.data || []
|
||||
// 默认选中激活版本
|
||||
const active = this.selectVersionList.find(v => v.isActive === 1)
|
||||
if (active) this.selectVersionId = active.versionId
|
||||
else if (this.selectVersionList.length) this.selectVersionId = this.selectVersionList[0].versionId
|
||||
})
|
||||
},
|
||||
confirmSelectRecipe() {
|
||||
if (!this.selectRecipeId) { this.$message.warning('请选择方案'); return }
|
||||
if (!this.selectVersionId) { this.$message.warning('请选择版本'); return }
|
||||
const r = this.recipeOptions.find(x => x.recipeId === this.selectRecipeId)
|
||||
const v = this.selectVersionList.find(x => x.versionId === this.selectVersionId)
|
||||
updateDrPlan({
|
||||
...this.selectedPlan,
|
||||
recipeId: this.selectRecipeId,
|
||||
recipeNo: r ? r.recipeNo : '',
|
||||
versionId: this.selectVersionId,
|
||||
passCount: r ? r.passCount : 0,
|
||||
}).then(() => {
|
||||
this.$message.success('方案绑定成功')
|
||||
this.selectRecipeVisible = false
|
||||
this.selectedPlan = {
|
||||
...this.selectedPlan,
|
||||
recipeId: this.selectRecipeId,
|
||||
recipeNo: r ? r.recipeNo : '',
|
||||
versionId: this.selectVersionId,
|
||||
}
|
||||
getDrRecipeVersionDetail(this.selectVersionId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
this.boundVersionCode = res.data ? res.data.versionCode : ''
|
||||
})
|
||||
this.loadList()
|
||||
})
|
||||
},
|
||||
enterEditMode() { this.openSelectRecipe() },
|
||||
onRecipeChange(recipeId) {
|
||||
if (!recipeId) return
|
||||
const r = this.recipeOptions.find(x => x.recipeId === recipeId)
|
||||
if (r) {
|
||||
if (!this.form.alloyNo) this.form.alloyNo = r.alloyNo
|
||||
if (!this.form.inMatThick) this.form.inMatThick = r.inThick
|
||||
if (!this.form.outThick) this.form.outThick = r.outThick
|
||||
if (!this.form.inMatWidth) this.form.inMatWidth = r.outWidth
|
||||
}
|
||||
},
|
||||
|
||||
handleAdd() { this.isNew = true; this.form = emptyForm(); this.planDialogVisible = true },
|
||||
handleEdit() { this.isNew = false; this.form = { ...this.selectedPlan }; this.planDialogVisible = true },
|
||||
handleSave() {
|
||||
this.$refs.formRef.validate(valid => {
|
||||
if (!valid) return
|
||||
if (this.form.recipeId) {
|
||||
const r = this.recipeOptions.find(x => x.recipeId === this.form.recipeId)
|
||||
if (r) { this.form.recipeNo = r.recipeNo; this.form.passCount = r.passCount }
|
||||
}
|
||||
const api = this.isNew ? addDrPlan : updateDrPlan
|
||||
api(this.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.planDialogVisible = false
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDelete() {
|
||||
this.$confirm(`确定删除该计划?`, '提示', { type: 'warning' }).then(() => {
|
||||
delDrPlan(this.selectedPlan.planId).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.selectedPlan = null; this.passList = []
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleFinish() {
|
||||
finishDrPlan(this.selectedPlan.planId).then(() => {
|
||||
this.$message.success('计划已完成')
|
||||
this.loadList()
|
||||
})
|
||||
},
|
||||
handleMoveUp() { moveUpDrPlan(this.selectedPlan.planId).then(() => this.loadList()) },
|
||||
handleMoveDown() { moveDownDrPlan(this.selectedPlan.planId).then(() => this.loadList()) },
|
||||
|
||||
queueRowClass({ row }) {
|
||||
if (row.prodStatus === 'Rolling') return 'row-rolling'
|
||||
return ''
|
||||
},
|
||||
passRowClass({ rowIndex }) { return rowIndex % 2 === 0 ? '' : 'alt-row' },
|
||||
prodStatusLabel(s) {
|
||||
return { Idle: '待轧', Rolling: '轧制中', NextCoil: '下一卷', Done: '已完成', Error: '异常' }[s] || s
|
||||
},
|
||||
prodStatusClass(s) {
|
||||
return { Idle: 'status-wait', Rolling: 'status-rolling', Done: 'status-done', Error: 'status-err' }[s] || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.plan-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background: #f5f7fa;
|
||||
padding: 8px 12px;
|
||||
box-sizing: border-box;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 16px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.recipe-tag {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #909399;
|
||||
background: #f0f2f5;
|
||||
padding: 2px 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.queue-section {
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.04);
|
||||
}
|
||||
.queue-table {
|
||||
::v-deep .row-rolling td { background: #fef3e2 !important; }
|
||||
::v-deep .el-table__row.current-row td { background: #ecf5ff !important; }
|
||||
}
|
||||
|
||||
.bottom-section { display: flex; flex: 1; gap: 8px; overflow: hidden; min-height: 0; }
|
||||
|
||||
.pass-panel {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.04);
|
||||
}
|
||||
.pass-empty {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
.pass-table {
|
||||
flex: 1;
|
||||
::v-deep .el-table__row.alt-row td { background: #fafafa !important; }
|
||||
}
|
||||
|
||||
.calc-val { font-family: 'Courier New', monospace; font-weight: 600; color: #409eff; }
|
||||
|
||||
.op-panel {
|
||||
width: 260px;
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
.query-form { padding: 10px 12px 4px; border-bottom: 1px solid #e4e7ed; }
|
||||
|
||||
.op-buttons {
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
.el-button { width: 100%; justify-content: flex-start; }
|
||||
}
|
||||
|
||||
.status-wait { color: #909399; }
|
||||
.status-rolling { color: #e6a23c; font-weight: 700; }
|
||||
.status-done { color: #409eff; }
|
||||
.status-err { color: #f56c6c; font-weight: 700; }
|
||||
</style>
|
||||
485
klp-ui/src/views/micro/pages/dr/components/ProcessSpec.vue
Normal file
485
klp-ui/src/views/micro/pages/dr/components/ProcessSpec.vue
Normal file
@@ -0,0 +1,485 @@
|
||||
<template>
|
||||
<div class="process-page">
|
||||
|
||||
<!-- 左栏:方案列表 -->
|
||||
<div class="col-panel left-panel">
|
||||
<div class="panel-header">
|
||||
<span>工艺方案</span>
|
||||
<el-button type="primary" size="mini" icon="el-icon-plus" @click="handleAddRecipe">新增</el-button>
|
||||
</div>
|
||||
<div class="search-bar">
|
||||
<el-input v-model="searchKey" placeholder="方案号/合金号" size="mini" clearable
|
||||
prefix-icon="el-icon-search" @input="loadRecipeList" />
|
||||
</div>
|
||||
<div class="item-list">
|
||||
<div v-for="r in recipeList" :key="r.recipeId"
|
||||
:class="['list-item', { active: selectedRecipeId === r.recipeId }]"
|
||||
@click="handleSelectRecipe(r)">
|
||||
<div class="item-main">{{ r.recipeNo }}</div>
|
||||
<div class="item-sub">{{ r.alloyNo }} · {{ r.inThick }}→{{ r.outThick }}mm</div>
|
||||
</div>
|
||||
<div v-if="!recipeList.length" class="empty-tip">暂无方案</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中栏:版本列表 -->
|
||||
<div class="col-panel mid-panel">
|
||||
<div class="panel-header">
|
||||
<span>版本列表</span>
|
||||
<el-button type="primary" size="mini" icon="el-icon-plus"
|
||||
:disabled="!selectedRecipeId" @click="handleAddVersion">新增版本</el-button>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
<div v-for="v in versionList" :key="v.versionId"
|
||||
:class="['list-item', { active: selectedVersionId === v.versionId }]"
|
||||
@click="handleSelectVersion(v)">
|
||||
<div class="item-main">
|
||||
{{ v.versionCode }}
|
||||
<el-tag v-if="v.isActive === 1" size="mini" type="success" style="margin-left:4px">激活</el-tag>
|
||||
<el-tag v-else-if="v.status === '1'" size="mini" type="info" style="margin-left:4px">已发布</el-tag>
|
||||
<el-tag v-else size="mini" style="margin-left:4px">草稿</el-tag>
|
||||
</div>
|
||||
<div class="item-sub">{{ v.remark }}</div>
|
||||
<div class="item-actions">
|
||||
<span v-if="v.isActive !== 1" class="action-link" @click.stop="handleActivate(v)">激活</span>
|
||||
<span class="action-link danger" @click.stop="handleDeleteVersion(v)">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedRecipeId && !versionList.length" class="empty-tip">暂无版本,请新增</div>
|
||||
<div v-if="!selectedRecipeId" class="empty-tip">请先选择方案</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右栏:版本详情 + 道次 -->
|
||||
<div class="right-panel">
|
||||
<div v-if="!versionForm.versionId && !isNewVersion" class="no-select">
|
||||
<i class="el-icon-document"></i>
|
||||
<p>请选择或新建版本</p>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<!-- 版本基本信息 -->
|
||||
<div class="detail-header">
|
||||
<span>{{ isNewVersion ? '新建版本' : versionForm.versionCode }}</span>
|
||||
<div class="btn-group">
|
||||
<el-button size="mini" type="primary" icon="el-icon-check" @click="handleSaveVersion">保存</el-button>
|
||||
<el-button size="mini" icon="el-icon-refresh" @click="handleResetVersion">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-form :model="versionForm" ref="versionFormRef" size="mini" label-width="76px"
|
||||
class="version-form" :rules="versionRules">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="5">
|
||||
<el-form-item label="版本号" prop="versionCode">
|
||||
<el-input v-model="versionForm.versionCode" placeholder="如 V1.0" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="versionForm.status" style="width:100%">
|
||||
<el-option label="草稿" value="0" />
|
||||
<el-option label="已发布" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="versionForm.remark" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<!-- 道次参数 -->
|
||||
<div class="pass-section">
|
||||
<div class="pass-header">
|
||||
<span>道次参数</span>
|
||||
<div class="btn-group">
|
||||
<el-button size="mini" icon="el-icon-plus" @click="addPass">增加道次</el-button>
|
||||
<el-button size="mini" icon="el-icon-minus" @click="removeLastPass" :disabled="!passList.length">删除末道</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="passList" border size="mini" class="pass-table"
|
||||
:row-class-name="passRowClass" height="calc(100vh - 310px)">
|
||||
<el-table-column label="道次" prop="passNo" width="50" align="center" fixed>
|
||||
<template slot-scope="{ row }"><b>{{ row.passNo }}</b></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口厚度(mm)" width="100" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.inThick" size="mini" @blur="calcPass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口厚度(mm)" width="100" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.outThick" size="mini" @blur="calcPass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="宽度(mm)" width="90" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.width" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="轧制力(kN)" width="90" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.rollForce" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口张力(kN)" width="95" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.inTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口张力(kN)" width="95" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.outTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最高速度(m/min)" width="110" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.maxSpeed" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口单位张力" width="100" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.inUnitTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口单位张力" width="100" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.outUnitTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="压下量(mm)" width="90" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.reduction }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总压下量(mm)" width="100" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.totalReduction }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" min-width="100">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.remark" size="mini" /></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑方案对话框 -->
|
||||
<el-dialog :title="recipeDialogTitle" :visible.sync="recipeDialogVisible" width="520px" append-to-body>
|
||||
<el-form :model="recipeForm" :rules="recipeRules" ref="recipeFormRef" size="small" label-width="88px">
|
||||
<el-form-item label="方案记录号" prop="recipeNo">
|
||||
<el-input v-model="recipeForm.recipeNo" :disabled="!!recipeForm.recipeId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合金号" prop="alloyNo">
|
||||
<el-input v-model="recipeForm.alloyNo" />
|
||||
</el-form-item>
|
||||
<el-form-item label="原料厚度">
|
||||
<el-input v-model="recipeForm.inThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="成品厚度">
|
||||
<el-input v-model="recipeForm.outThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="成品宽度">
|
||||
<el-input v-model="recipeForm.outWidth"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="recipeDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitRecipe">确定</el-button>
|
||||
<el-button v-if="recipeForm.recipeId" type="danger" @click="handleDeleteRecipe">删除</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listDrRecipe, addDrRecipe, updateDrRecipe, delDrRecipe,
|
||||
listDrRecipeVersions, getDrRecipeVersionDetail,
|
||||
addDrRecipeVersion, updateDrRecipeVersion,
|
||||
activateDrRecipeVersion, delDrRecipeVersion
|
||||
} from '@/api/wms/drMill'
|
||||
|
||||
const emptyPass = (no) => ({
|
||||
passNo: no, inThick: '', outThick: '', width: '',
|
||||
rollForce: '', inTension: '', outTension: '',
|
||||
maxSpeed: '', inUnitTension: '', outUnitTension: '',
|
||||
reduction: '', totalReduction: '', remark: ''
|
||||
})
|
||||
|
||||
const emptyVersionForm = () => ({
|
||||
versionId: null, recipeId: null, versionCode: '', status: '0', remark: ''
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'DrProcessTab',
|
||||
data() {
|
||||
return {
|
||||
// 方案
|
||||
searchKey: '',
|
||||
recipeList: [],
|
||||
selectedRecipeId: null,
|
||||
recipeDialogVisible: false,
|
||||
recipeDialogTitle: '新增工艺方案',
|
||||
recipeForm: {},
|
||||
recipeRules: {
|
||||
recipeNo: [{ required: true, message: '请输入方案记录号', trigger: 'blur' }],
|
||||
alloyNo: [{ required: true, message: '请输入合金号', trigger: 'blur' }],
|
||||
},
|
||||
// 版本
|
||||
versionList: [],
|
||||
selectedVersionId: null,
|
||||
isNewVersion: false,
|
||||
versionForm: emptyVersionForm(),
|
||||
versionRules: {
|
||||
versionCode: [{ required: true, message: '请输入版本号', trigger: 'blur' }],
|
||||
},
|
||||
// 道次
|
||||
passList: [],
|
||||
}
|
||||
},
|
||||
mounted() { this.loadRecipeList() },
|
||||
methods: {
|
||||
// ── 方案 ──────────────────────────────────────────────────
|
||||
loadRecipeList() {
|
||||
listDrRecipe({ recipeNo: this.searchKey, alloyNo: this.searchKey }).then(res => {
|
||||
this.recipeList = res.data || []
|
||||
})
|
||||
},
|
||||
handleSelectRecipe(r) {
|
||||
this.selectedRecipeId = r.recipeId
|
||||
this.isNewVersion = false
|
||||
this.selectedVersionId = null
|
||||
this.versionForm = emptyVersionForm()
|
||||
this.passList = []
|
||||
this.loadVersionList(r.recipeId)
|
||||
},
|
||||
handleAddRecipe() {
|
||||
this.recipeForm = { recipeNo: '', alloyNo: '', inThick: '', outThick: '', outWidth: '', status: '0' }
|
||||
this.recipeDialogTitle = '新增工艺方案'
|
||||
this.recipeDialogVisible = true
|
||||
},
|
||||
handleEditRecipe(r) {
|
||||
this.recipeForm = { ...r }
|
||||
this.recipeDialogTitle = '编辑工艺方案'
|
||||
this.recipeDialogVisible = true
|
||||
},
|
||||
submitRecipe() {
|
||||
this.$refs.recipeFormRef.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.recipeForm.recipeId ? updateDrRecipe : addDrRecipe
|
||||
api(this.recipeForm).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.recipeDialogVisible = false
|
||||
this.loadRecipeList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteRecipe() {
|
||||
this.$confirm('确定删除该方案及所有版本?', '提示', { type: 'warning' }).then(() => {
|
||||
delDrRecipe([this.recipeForm.recipeId]).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.recipeDialogVisible = false
|
||||
this.selectedRecipeId = null
|
||||
this.versionList = []
|
||||
this.versionForm = emptyVersionForm()
|
||||
this.passList = []
|
||||
this.loadRecipeList()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// ── 版本 ──────────────────────────────────────────────────
|
||||
loadVersionList(recipeId) {
|
||||
listDrRecipeVersions(recipeId).then(res => {
|
||||
this.versionList = res.data || []
|
||||
})
|
||||
},
|
||||
handleSelectVersion(v) {
|
||||
this.selectedVersionId = v.versionId
|
||||
this.isNewVersion = false
|
||||
getDrRecipeVersionDetail(v.versionId).then(res => {
|
||||
this.versionForm = { ...res.data }
|
||||
this.passList = (res.data.passList || []).map(p => ({ ...p }))
|
||||
})
|
||||
},
|
||||
handleAddVersion() {
|
||||
this.isNewVersion = true
|
||||
this.selectedVersionId = null
|
||||
this.versionForm = { ...emptyVersionForm(), recipeId: this.selectedRecipeId }
|
||||
this.passList = []
|
||||
},
|
||||
handleSaveVersion() {
|
||||
this.$refs.versionFormRef.validate(valid => {
|
||||
if (!valid) return
|
||||
this.versionForm.passList = this.passList
|
||||
const api = this.isNewVersion ? addDrRecipeVersion : updateDrRecipeVersion
|
||||
api(this.versionForm).then(res => {
|
||||
this.$message.success('保存成功')
|
||||
this.isNewVersion = false
|
||||
if (res.data) this.versionForm.versionId = res.data
|
||||
this.loadVersionList(this.selectedRecipeId)
|
||||
})
|
||||
})
|
||||
},
|
||||
handleResetVersion() {
|
||||
if (this.isNewVersion) {
|
||||
this.versionForm = { ...emptyVersionForm(), recipeId: this.selectedRecipeId }
|
||||
this.passList = []
|
||||
} else {
|
||||
this.handleSelectVersion({ versionId: this.selectedVersionId })
|
||||
}
|
||||
},
|
||||
handleActivate(v) {
|
||||
this.$confirm(`确定激活版本 ${v.versionCode}?`, '提示', { type: 'warning' }).then(() => {
|
||||
activateDrRecipeVersion(v.versionId).then(() => {
|
||||
this.$message.success('激活成功')
|
||||
this.loadVersionList(this.selectedRecipeId)
|
||||
if (this.selectedVersionId === v.versionId) {
|
||||
this.versionForm.isActive = 1
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteVersion(v) {
|
||||
this.$confirm(`确定删除版本 ${v.versionCode}?`, '提示', { type: 'warning' }).then(() => {
|
||||
delDrRecipeVersion(v.versionId).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
if (this.selectedVersionId === v.versionId) {
|
||||
this.selectedVersionId = null
|
||||
this.versionForm = emptyVersionForm()
|
||||
this.passList = []
|
||||
}
|
||||
this.loadVersionList(this.selectedRecipeId)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// ── 道次 ──────────────────────────────────────────────────
|
||||
addPass() { this.passList.push(emptyPass(this.passList.length + 1)) },
|
||||
removeLastPass() { if (this.passList.length) this.passList.pop() },
|
||||
calcPass(row) {
|
||||
const inT = parseFloat(row.inThick) || 0
|
||||
const outT = parseFloat(row.outThick) || 0
|
||||
row.reduction = outT > 0 ? (inT - outT).toFixed(3) : ''
|
||||
const base = parseFloat(this.passList[0] && this.passList[0].inThick) || 0
|
||||
for (const p of this.passList) {
|
||||
const pOut = parseFloat(p.outThick) || 0
|
||||
if (base > 0 && pOut > 0) p.totalReduction = parseFloat((base - pOut).toFixed(3))
|
||||
}
|
||||
},
|
||||
passRowClass({ rowIndex }) { return rowIndex % 2 === 0 ? '' : 'alt-row' }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.process-page {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
gap: 0;
|
||||
background: #f5f7fa;
|
||||
padding: 10px 12px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.col-panel {
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-right: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.04);
|
||||
}
|
||||
.left-panel { width: 200px; }
|
||||
.mid-panel { width: 220px; }
|
||||
|
||||
.panel-header {
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
padding: 10px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.search-bar { padding: 6px 8px; border-bottom: 1px solid #e4e7ed; flex-shrink: 0; }
|
||||
|
||||
.item-list { flex: 1; overflow-y: auto; }
|
||||
|
||||
.list-item {
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
cursor: pointer;
|
||||
transition: background .15s;
|
||||
&:hover { background: #f5f7fa; }
|
||||
&.active {
|
||||
background: #ecf5ff;
|
||||
border-left: 3px solid #409eff;
|
||||
}
|
||||
.item-main { font-size: 13px; font-weight: 600; color: #303133; }
|
||||
.item-sub { font-size: 12px; color: #909399; margin-top: 2px; }
|
||||
.item-actions {
|
||||
display: flex; gap: 8px; margin-top: 4px;
|
||||
.action-link {
|
||||
font-size: 12px; color: #409eff; cursor: pointer;
|
||||
&:hover { text-decoration: underline; }
|
||||
&.danger { color: #f56c6c; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-tip { text-align: center; color: #c0c4cc; padding: 24px 0; font-size: 13px; }
|
||||
|
||||
.right-panel {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
.no-select {
|
||||
flex: 1; display: flex; flex-direction: column; align-items: center;
|
||||
justify-content: center; color: #c0c4cc; font-size: 13px;
|
||||
i { font-size: 48px; margin-bottom: 10px; }
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
padding: 10px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btn-group { display: flex; gap: 6px; }
|
||||
|
||||
.version-form { padding: 8px 12px 4px; flex-shrink: 0; border-bottom: 1px solid #e4e7ed; }
|
||||
|
||||
.pass-section { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
|
||||
|
||||
.pass-header {
|
||||
padding: 8px 16px;
|
||||
background: #fafafa;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pass-table {
|
||||
flex: 1;
|
||||
::v-deep .el-table__row.alt-row td { background: #fafafa !important; }
|
||||
::v-deep .el-input__inner { text-align: right; padding: 0 4px !important; }
|
||||
}
|
||||
|
||||
.calc-val { font-family: 'Courier New', monospace; font-weight: 600; color: #409eff; }
|
||||
</style>
|
||||
89
klp-ui/src/views/micro/pages/dr/index.vue
Normal file
89
klp-ui/src/views/micro/pages/dr/index.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div class="dr-container">
|
||||
<div class="dr-sidebar">
|
||||
<el-menu :default-active="activeMenu" class="sidebar-menu" @select="handleMenuSelect">
|
||||
<el-menu-item index="plan">
|
||||
<i class="el-icon-s-order"></i>
|
||||
<span slot="title">计划</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="processSpec">
|
||||
<i class="el-icon-s-tools"></i>
|
||||
<span slot="title">规程</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="actual">
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span slot="title">实绩</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</div>
|
||||
<div style="flex:1;overflow:hidden;">
|
||||
<component :is="currentComponent" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Plan from './components/Plan.vue'
|
||||
import ProcessSpec from './components/ProcessSpec.vue'
|
||||
import Actual from './components/Actual.vue'
|
||||
|
||||
export default {
|
||||
name: 'DrSystem',
|
||||
components: { Plan, ProcessSpec, Actual },
|
||||
data() {
|
||||
return { activeMenu: 'plan' }
|
||||
},
|
||||
computed: {
|
||||
currentComponent() {
|
||||
return { plan: 'Plan', processSpec: 'ProcessSpec', actual: 'Actual' }[this.activeMenu]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleMenuSelect(index) { this.activeMenu = index }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dr-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: calc(100vh - 84px);
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.dr-sidebar {
|
||||
width: 100px;
|
||||
background-color: #fff;
|
||||
border-right: 1px solid #e4e7ed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 2px 0 8px rgba(0,0,0,.05);
|
||||
|
||||
.sidebar-menu {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
border-right: none;
|
||||
|
||||
::v-deep .el-menu-item {
|
||||
color: #606266;
|
||||
padding: 0 20px;
|
||||
font-size: 14px;
|
||||
|
||||
i {
|
||||
font-size: 18px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&:hover { background-color: #ecf5ff; color: #409eff; }
|
||||
&.is-active {
|
||||
background-color: #ecf5ff;
|
||||
color: #409eff;
|
||||
border-right: 3px solid #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
355
klp-ui/src/views/timing/acid/rollConfig.vue
Normal file
355
klp-ui/src/views/timing/acid/rollConfig.vue
Normal file
@@ -0,0 +1,355 @@
|
||||
<template>
|
||||
<div class="roll-config-view">
|
||||
<div class="toolbar">
|
||||
<span class="page-title"><i class="el-icon-s-tools" /> 酸轧配辊</span>
|
||||
<div class="toolbar-right">
|
||||
<span v-if="lastRefresh" class="refresh-time">上次刷新:{{ lastRefresh }}</span>
|
||||
<el-button size="small" @click="handleCheck">
|
||||
<i class="el-icon-search" /> 缺辊检查
|
||||
</el-button>
|
||||
<el-button size="small" type="primary" :loading="loading" @click="loadData">
|
||||
<i class="el-icon-refresh" /> 刷新
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-wrap" v-loading="loading">
|
||||
<table class="roll-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" class="th-stand">机架</th>
|
||||
<th rowspan="2" class="th-pos">位置</th>
|
||||
<th colspan="4" class="th-section th-standby">备 辊</th>
|
||||
<th colspan="9" class="th-section th-online">在线辊</th>
|
||||
<th colspan="4" class="th-section th-standard">换辊参考</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<!-- 备辊 -->
|
||||
<th class="th-sub">辊号</th>
|
||||
<th class="th-sub">外径(mm)</th>
|
||||
<th class="th-sub">凸度</th>
|
||||
<th class="th-sub">粗糙度</th>
|
||||
<!-- 在线辊 -->
|
||||
<th class="th-sub">辊号</th>
|
||||
<th class="th-sub">上/下</th>
|
||||
<th class="th-sub">辊型</th>
|
||||
<th class="th-sub">直径(mm)</th>
|
||||
<th class="th-sub">凸度</th>
|
||||
<th class="th-sub">粗糙度</th>
|
||||
<th class="th-sub">本次长度</th>
|
||||
<th class="th-sub">本次重量</th>
|
||||
<th class="th-sub">安装时间</th>
|
||||
<!-- 换辊参考 -->
|
||||
<th class="th-sub">本次长度</th>
|
||||
<th class="th-sub">累计长度</th>
|
||||
<th class="th-sub">本次重量</th>
|
||||
<th class="th-sub">累计重量</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(stand, si) in tableData">
|
||||
<tr
|
||||
v-for="(pos, pi) in stand.positions"
|
||||
:key="stand.id + '-' + pi"
|
||||
:class="rowCls(pos, pi)"
|
||||
>
|
||||
<td v-if="pi === 0" :rowspan="stand.positions.length" class="td-stand">
|
||||
{{ stand.name }}
|
||||
</td>
|
||||
<td class="td-pos" :class="posTypeCls(pos)">{{ pos.label }}</td>
|
||||
|
||||
<!-- 备辊 -->
|
||||
<td class="td-standby">{{ sv(pos.standby, 'rollid') }}</td>
|
||||
<td class="td-standby">{{ nv(pos.standby, 'diameter') }}</td>
|
||||
<td class="td-standby">{{ nv(pos.standby, 'crown') }}</td>
|
||||
<td class="td-standby">{{ nv(pos.standby, 'rough') }}</td>
|
||||
|
||||
<!-- 在线辊 -->
|
||||
<td class="td-online td-bold">{{ sv(pos.online, 'rollid') }}</td>
|
||||
<td class="td-online">{{ dispPos(pos.online && pos.online.position) }}</td>
|
||||
<td class="td-online">
|
||||
<span :class="typeChipCls(pos.online && pos.online.type)">
|
||||
{{ dispType(pos.online && pos.online.type) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="td-online">{{ nv(pos.online, 'diameter') }}</td>
|
||||
<td class="td-online">{{ nv(pos.online, 'crown') }}</td>
|
||||
<td class="td-online">{{ nv(pos.online, 'rough') }}</td>
|
||||
<td class="td-online">{{ iv(pos.online, 'rolled_length') }}</td>
|
||||
<td class="td-online">{{ iv(pos.online, 'rolled_weight') }}</td>
|
||||
<td class="td-online td-time">{{ dv(pos.online, 'instal_time') }}</td>
|
||||
|
||||
<!-- 换辊参考 -->
|
||||
<td class="td-std">{{ iv(pos.online, 'rolled_length') }}</td>
|
||||
<td class="td-std">{{ iv(pos.online, 'total_rolled_length') }}</td>
|
||||
<td class="td-std">{{ iv(pos.online, 'rolled_weight') }}</td>
|
||||
<td class="td-std">{{ iv(pos.online, 'total_rolled_weight') }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getRollData } from '@/api/l2/timing'
|
||||
|
||||
// 酸轧(PLTCM)六机架
|
||||
const STAND_NAMES = ['1#机架', '2#机架', '3#机架', '4#机架', '5#机架', '6#机架']
|
||||
|
||||
const POS_NORM = {
|
||||
TOP: '上', UPPER: '上', UP: '上', '上': '上',
|
||||
BOTTOM: '下', LOWER: '下', DOWN: '下', '下': '下'
|
||||
}
|
||||
const TYPE_NORM = {
|
||||
WORK: '工作辊', WORK_ROLL: '工作辊', WR: '工作辊', '工作辊': '工作辊',
|
||||
BACKUP: '支撑辊', BUR: '支撑辊', SUPPORT: '支撑辊', BACK_UP: '支撑辊', '支撑辊': '支撑辊',
|
||||
INTERMEDIATE: '中间辊', IMR: '中间辊', INTER: '中间辊', '中间辊': '中间辊'
|
||||
}
|
||||
|
||||
function normPos(v) { return POS_NORM[String(v || '').toUpperCase()] || String(v || '').trim() }
|
||||
function normType(v) { return TYPE_NORM[String(v || '').toUpperCase()] || String(v || '').trim() }
|
||||
|
||||
// 酸轧六辊轧机(UCM)辊系排列:支撑辊 + 中间辊 + 工作辊
|
||||
const POSITIONS = [
|
||||
{ label: '上支撑辊', position: '上', type: '支撑辊', group: 'bur' },
|
||||
{ label: '上中间辊', position: '上', type: '中间辊', group: 'imr' },
|
||||
{ label: '上工作辊', position: '上', type: '工作辊', group: 'wr' },
|
||||
{ label: '下工作辊', position: '下', type: '工作辊', group: 'wr' },
|
||||
{ label: '下中间辊', position: '下', type: '中间辊', group: 'imr' },
|
||||
{ label: '下支撑辊', position: '下', type: '支撑辊', group: 'bur' }
|
||||
]
|
||||
|
||||
function fmtDateStr(val) {
|
||||
if (!val) return '—'
|
||||
const s = String(val)
|
||||
const m = s.match(/(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2})/)
|
||||
if (m) return `${m[1]}-${m[2]}-${m[3]} ${m[4]}:${m[5]}`
|
||||
const d = new Date(val)
|
||||
if (isNaN(d.getTime())) return s.substring(0, 16)
|
||||
const pad = n => String(n).padStart(2, '0')
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'AcidRollConfigPage',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
lastRefresh: '',
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await getRollData()
|
||||
const rows = res?.data?.rows || []
|
||||
this.buildTableData(rows)
|
||||
const now = new Date()
|
||||
const pad = n => String(n).padStart(2, '0')
|
||||
this.lastRefresh = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
buildTableData(rows) {
|
||||
this.tableData = STAND_NAMES.map((name, idx) => {
|
||||
const standId = idx + 1
|
||||
const standRows = rows.filter(r => Number(r.standid) === standId)
|
||||
const positions = POSITIONS.map(p => {
|
||||
const matches = standRows
|
||||
.filter(r => normPos(r.position) === p.position && normType(r.type) === p.type)
|
||||
.sort((a, b) => {
|
||||
const ta = a.instal_time ? new Date(a.instal_time).getTime() : 0
|
||||
const tb = b.instal_time ? new Date(b.instal_time).getTime() : 0
|
||||
return ta - tb
|
||||
})
|
||||
return { ...p, online: matches[0] || null, standby: matches[1] || null }
|
||||
})
|
||||
return { id: standId, name, positions }
|
||||
})
|
||||
},
|
||||
rowCls(pos, pi) {
|
||||
const cls = []
|
||||
if (!pos.online) cls.push('row-empty')
|
||||
if (pi === 2 || pi === 3) cls.push('row-wr') // 工作辊行分隔线
|
||||
return cls.join(' ')
|
||||
},
|
||||
posTypeCls(pos) {
|
||||
const map = { bur: 'pos-bur', imr: 'pos-imr', wr: 'pos-wr' }
|
||||
return map[pos.group] || ''
|
||||
},
|
||||
typeChipCls(type) {
|
||||
const t = normType(type)
|
||||
if (t === '工作辊') return 'chip chip-wr'
|
||||
if (t === '中间辊') return 'chip chip-imr'
|
||||
if (t === '支撑辊') return 'chip chip-bur'
|
||||
return ''
|
||||
},
|
||||
sv(row, key) {
|
||||
if (!row) return '—'
|
||||
const v = row[key]
|
||||
return v != null && v !== '' ? String(v) : '—'
|
||||
},
|
||||
nv(row, key) {
|
||||
if (!row) return '—'
|
||||
const v = row[key]
|
||||
if (v == null || v === '') return '—'
|
||||
const n = parseFloat(v)
|
||||
return isNaN(n) ? String(v) : n.toFixed(2)
|
||||
},
|
||||
iv(row, key) {
|
||||
if (!row) return '—'
|
||||
const v = row[key]
|
||||
if (v == null || v === '') return '—'
|
||||
const n = parseFloat(v)
|
||||
return isNaN(n) ? String(v) : Math.round(n).toLocaleString()
|
||||
},
|
||||
dv(row, key) { return row ? fmtDateStr(row[key]) : '—' },
|
||||
dispPos(v) { return POS_NORM[String(v || '').toUpperCase()] || v || '—' },
|
||||
dispType(v) { return TYPE_NORM[String(v || '').toUpperCase()] || v || '—' },
|
||||
handleCheck() {
|
||||
const missing = []
|
||||
this.tableData.forEach(stand => {
|
||||
stand.positions.forEach(pos => {
|
||||
if (pos.online && !pos.standby) missing.push(`${stand.name} ${pos.label}`)
|
||||
})
|
||||
})
|
||||
if (!missing.length) {
|
||||
this.$message.success('检查通过,各机架备辊配置正常')
|
||||
} else {
|
||||
this.$alert(missing.join('\n'), '以下位置缺少备辊', { type: 'warning', confirmButtonText: '知道了' })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.roll-config-view {
|
||||
padding: 12px 16px;
|
||||
background: #fff;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* ── 工具栏 ── */
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.refresh-time {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
/* ── 表格容器 ── */
|
||||
.table-wrap {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* ── 轧辊表 ── */
|
||||
.roll-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 12px;
|
||||
color: #303133;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.roll-table th,
|
||||
.roll-table td {
|
||||
border: 1px solid #e4e7ed;
|
||||
padding: 5px 9px;
|
||||
text-align: center;
|
||||
}
|
||||
.roll-table thead tr:first-child th {
|
||||
background: #eef1f6;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
}
|
||||
.th-section { border-bottom: 2px solid #b8c2cc !important; }
|
||||
.th-standby { background: #f5f7fa !important; color: #606266; }
|
||||
.th-online { background: #e8f4ff !important; color: #1a5276; }
|
||||
.th-standard{ background: #fdf6ec !important; color: #7b5c1e; }
|
||||
.th-stand, .th-pos { background: #eef1f6; font-weight: 600; }
|
||||
.th-sub {
|
||||
background: #fafafa;
|
||||
font-weight: normal;
|
||||
font-size: 11px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
/* 机架单元格(竖向文字) */
|
||||
.td-stand {
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
background: #f0f3f8;
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: mixed;
|
||||
letter-spacing: 3px;
|
||||
width: 30px;
|
||||
min-width: 30px;
|
||||
}
|
||||
|
||||
/* 辊位名称列 */
|
||||
.td-pos {
|
||||
font-weight: 500;
|
||||
width: 64px;
|
||||
text-align: left;
|
||||
padding-left: 8px;
|
||||
}
|
||||
.pos-bur { background: #f5f7fa; color: #5a6a7e; }
|
||||
.pos-imr { background: #f0f9eb; color: #3a7a2a; }
|
||||
.pos-wr { background: #e8f4ff; color: #1a5276; font-weight: 600; }
|
||||
|
||||
/* 工作辊行加粗上边框 */
|
||||
.row-wr td { border-top: 2px solid #c8d8ea !important; }
|
||||
|
||||
/* 辊型 chip */
|
||||
.chip {
|
||||
display: inline-block;
|
||||
padding: 1px 7px;
|
||||
border-radius: 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.chip-bur { background: #f5f7fa; color: #5a6a7e; border: 1px solid #dcdfe6; }
|
||||
.chip-imr { background: #f0f9eb; color: #3a7a2a; border: 1px solid #b3e19d; }
|
||||
.chip-wr { background: #e8f4ff; color: #1a5276; border: 1px solid #a0c4e8; }
|
||||
|
||||
.td-bold { font-weight: 600; }
|
||||
.td-standby { color: #606266; }
|
||||
.td-online { color: #303133; }
|
||||
.td-std { color: #909399; }
|
||||
.td-time { font-size: 11px; color: #909399; min-width: 110px; }
|
||||
.row-empty td { color: #c0c4cc; background: #fafafa; }
|
||||
.roll-table tbody tr:hover td { background: #f0f7ff; }
|
||||
</style>
|
||||
273
klp-ui/src/views/timing/acid/rollHistory.vue
Normal file
273
klp-ui/src/views/timing/acid/rollHistory.vue
Normal file
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<div class="roll-history-view">
|
||||
<!-- 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<span class="page-title"><i class="el-icon-time" /> 酸轧换辊历史</span>
|
||||
<div class="filter-right">
|
||||
<el-form :inline="true" :model="query" size="small" style="margin:0">
|
||||
<el-form-item label="轧辊号">
|
||||
<el-input
|
||||
v-model="query.rollId"
|
||||
placeholder="输入轧辊号"
|
||||
clearable
|
||||
style="width:160px"
|
||||
@keyup.enter.native="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="机架">
|
||||
<el-select v-model="query.standId" placeholder="全部" clearable style="width:110px">
|
||||
<el-option v-for="s in standOptions" :key="s.value" :label="s.label" :value="s.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="辊型">
|
||||
<el-select v-model="query.rollType" placeholder="全部" clearable style="width:100px">
|
||||
<el-option label="工作辊" value="WORK" />
|
||||
<el-option label="中间辊" value="INTERMEDIATE" />
|
||||
<el-option label="支撑辊" value="BACKUP" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" :loading="loading" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表 -->
|
||||
<el-table
|
||||
:data="rows"
|
||||
size="mini"
|
||||
border
|
||||
stripe
|
||||
:height="tableHeight"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
>
|
||||
<el-table-column type="index" width="48" label="序" fixed align="center" />
|
||||
<el-table-column prop="rollid" label="轧辊号" width="120" fixed show-overflow-tooltip />
|
||||
<el-table-column label="机架" width="72" align="center">
|
||||
<template slot-scope="{ row }">{{ standName(row.standid) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="位置" width="52" align="center">
|
||||
<template slot-scope="{ row }">{{ dispPos(row.position) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="辊型" width="80" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span :class="typeChipCls(row.type)">{{ dispType(row.type) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="diameter" label="直径(mm)" width="90" align="right" :formatter="fmtNum" />
|
||||
<el-table-column prop="crown" label="凸度" width="72" align="right" :formatter="fmtNum" />
|
||||
<el-table-column prop="rough" label="粗糙度" width="72" align="right" :formatter="fmtNum" />
|
||||
<el-table-column prop="rolled_length" label="本次长度" width="90" align="right" :formatter="fmtInt" />
|
||||
<el-table-column prop="rolled_weight" label="本次重量" width="90" align="right" :formatter="fmtInt" />
|
||||
<el-table-column prop="total_rolled_length" label="累计长度" width="90" align="right" :formatter="fmtInt" />
|
||||
<el-table-column prop="total_rolled_weight" label="累计重量" width="90" align="right" :formatter="fmtInt" />
|
||||
<el-table-column prop="grind_count" label="磨削次数" width="80" align="center" />
|
||||
<el-table-column label="安装时间" width="140" align="center">
|
||||
<template slot-scope="{ row }">{{ fmtDate(row.instal_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="卸辊时间" width="140" align="center">
|
||||
<template slot-scope="{ row }">{{ fmtDate(row.deinstal_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="换辊时间" width="140" align="center">
|
||||
<template slot-scope="{ row }">{{ fmtDate(row.change_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="shift" label="班次" width="52" align="center" />
|
||||
<el-table-column prop="crew" label="班组" width="52" align="center" />
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-bar">
|
||||
<el-pagination
|
||||
small
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pagination.total"
|
||||
:page-size="pagination.pageSize"
|
||||
:page-sizes="[50, 100, 200]"
|
||||
:current-page="pagination.page"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getRollHistoryList, getRollHistoryCount } from '@/api/l2/timing'
|
||||
|
||||
// 酸轧六机架
|
||||
const STAND_NAMES = ['1#机架', '2#机架', '3#机架', '4#机架', '5#机架', '6#机架']
|
||||
|
||||
const POS_NORM = {
|
||||
TOP: '上', UPPER: '上', UP: '上', '上': '上',
|
||||
BOTTOM: '下', LOWER: '下', DOWN: '下', '下': '下'
|
||||
}
|
||||
const TYPE_NORM = {
|
||||
WORK: '工作辊', WORK_ROLL: '工作辊', WR: '工作辊', '工作辊': '工作辊',
|
||||
BACKUP: '支撑辊', BUR: '支撑辊', SUPPORT: '支撑辊', BACK_UP: '支撑辊', '支撑辊': '支撑辊',
|
||||
INTERMEDIATE: '中间辊', IMR: '中间辊', INTER: '中间辊', '中间辊': '中间辊'
|
||||
}
|
||||
|
||||
function fmtDateStr(val) {
|
||||
if (!val) return '—'
|
||||
const s = String(val)
|
||||
const m = s.match(/(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2})/)
|
||||
if (m) return `${m[1]}-${m[2]}-${m[3]} ${m[4]}:${m[5]}`
|
||||
const d = new Date(val)
|
||||
if (isNaN(d.getTime())) return s.substring(0, 16)
|
||||
const pad = n => String(n).padStart(2, '0')
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'AcidRollHistoryPage',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
query: { rollId: '', standId: null, rollType: '' },
|
||||
rows: [],
|
||||
pagination: { page: 1, pageSize: 50, total: 0 },
|
||||
tableHeight: 'calc(100vh - 172px)',
|
||||
standOptions: STAND_NAMES.map((label, i) => ({ label, value: i + 1 }))
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadCount()
|
||||
this.loadRows()
|
||||
},
|
||||
methods: {
|
||||
async loadCount() {
|
||||
try {
|
||||
const res = await getRollHistoryCount(
|
||||
this.query.rollId || undefined,
|
||||
this.query.standId || undefined
|
||||
)
|
||||
this.pagination.total = res?.data?.total ?? 0
|
||||
} catch (_) {}
|
||||
},
|
||||
async loadRows() {
|
||||
this.loading = true
|
||||
try {
|
||||
const { page, pageSize } = this.pagination
|
||||
const res = await getRollHistoryList(
|
||||
page, pageSize,
|
||||
this.query.rollId || undefined,
|
||||
this.query.standId || undefined
|
||||
)
|
||||
let rows = res?.data?.rows || []
|
||||
// 前端按辊型过滤(接口暂不支持辊型参数)
|
||||
if (this.query.rollType) {
|
||||
const norm = TYPE_NORM[this.query.rollType] || this.query.rollType
|
||||
rows = rows.filter(r => {
|
||||
const t = String(r.type || '').toUpperCase()
|
||||
return TYPE_NORM[t] === norm || String(r.type || '') === norm
|
||||
})
|
||||
}
|
||||
this.rows = rows
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
handleSearch() {
|
||||
this.pagination.page = 1
|
||||
this.loadCount()
|
||||
this.loadRows()
|
||||
},
|
||||
handleReset() {
|
||||
this.query = { rollId: '', standId: null, rollType: '' }
|
||||
this.pagination.page = 1
|
||||
this.loadCount()
|
||||
this.loadRows()
|
||||
},
|
||||
handlePageChange(page) {
|
||||
this.pagination.page = page
|
||||
this.loadRows()
|
||||
},
|
||||
handleSizeChange(size) {
|
||||
this.pagination.pageSize = size
|
||||
this.pagination.page = 1
|
||||
this.loadCount()
|
||||
this.loadRows()
|
||||
},
|
||||
standName(val) {
|
||||
const idx = Number(val) - 1
|
||||
return STAND_NAMES[idx] || (val != null ? String(val) : '—')
|
||||
},
|
||||
dispPos(v) { return POS_NORM[String(v || '').toUpperCase()] || v || '—' },
|
||||
dispType(v) { return TYPE_NORM[String(v || '').toUpperCase()] || v || '—' },
|
||||
typeChipCls(type) {
|
||||
const t = String(type || '').toUpperCase()
|
||||
const norm = TYPE_NORM[t] || ''
|
||||
if (norm === '工作辊') return 'chip chip-wr'
|
||||
if (norm === '中间辊') return 'chip chip-imr'
|
||||
if (norm === '支撑辊') return 'chip chip-bur'
|
||||
return ''
|
||||
},
|
||||
fmtNum(row, col, val) {
|
||||
if (val == null || val === '') return '—'
|
||||
const n = parseFloat(val)
|
||||
return isNaN(n) ? String(val) : n.toFixed(2)
|
||||
},
|
||||
fmtInt(row, col, val) {
|
||||
if (val == null || val === '') return '—'
|
||||
const n = parseFloat(val)
|
||||
return isNaN(n) ? String(val) : Math.round(n).toLocaleString()
|
||||
},
|
||||
fmtDate(val) { return fmtDateStr(val) }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.roll-history-view {
|
||||
padding: 12px 16px;
|
||||
background: #fff;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* ── 筛选栏 ── */
|
||||
.filter-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.page-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.filter-right { display: flex; align-items: center; }
|
||||
|
||||
/* ── 辊型 chip ── */
|
||||
.chip {
|
||||
display: inline-block;
|
||||
padding: 1px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.chip-bur { background: #f5f7fa; color: #5a6a7e; border: 1px solid #dcdfe6; }
|
||||
.chip-imr { background: #f0f9eb; color: #3a7a2a; border: 1px solid #b3e19d; }
|
||||
.chip-wr { background: #e8f4ff; color: #1a5276; border: 1px solid #a0c4e8; }
|
||||
|
||||
/* ── 分页 ── */
|
||||
.pagination-bar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 8px 0 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
243
klp-ui/src/views/wms/coil/do/dr-normal.vue
Normal file
243
klp-ui/src/views/wms/coil/do/dr-normal.vue
Normal file
@@ -0,0 +1,243 @@
|
||||
<template>
|
||||
<div class="app-container acid-op-page">
|
||||
<el-row :gutter="16">
|
||||
|
||||
<!-- 左侧:操作表单 + 历史记录 -->
|
||||
<el-col :span="15">
|
||||
|
||||
<div class="op-card">
|
||||
<div class="op-header">
|
||||
<span class="op-title">双机架工序录入</span>
|
||||
<el-tag size="mini" type="info" style="margin-left:8px">actionType = 504</el-tag>
|
||||
</div>
|
||||
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="110px" size="small">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="入场钢卷号" prop="enterCoilNo">
|
||||
<el-input v-model="form.enterCoilNo" placeholder="回车自动查询"
|
||||
clearable @keyup.enter.native="onEnterCoilInput" @blur="onEnterCoilInput" @clear="clearCoilInfo" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="出口钢卷号" prop="currentCoilNo">
|
||||
<el-input v-model="form.currentCoilNo" placeholder="请输入出口钢卷号" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left" style="margin:8px 0 12px">出口实绩</el-divider>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出口厚度(mm)" prop="exitThickness">
|
||||
<el-input-number v-model="form.exitThickness" :precision="3" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出口宽度(mm)" prop="exitWidth">
|
||||
<el-input-number v-model="form.exitWidth" :precision="1" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出口长度(m)">
|
||||
<el-input-number v-model="form.exitLength" :precision="1" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="入口重量(t)">
|
||||
<el-input-number v-model="form.entryWeight" :precision="3" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出口重量(t)">
|
||||
<el-input-number v-model="form.exitWeight" :precision="3" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="工艺编码">
|
||||
<el-input v-model="form.processCode" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="班组">
|
||||
<el-select v-model="form.team" placeholder="请选择" style="width:100%" clearable>
|
||||
<el-option label="甲班" value="甲" />
|
||||
<el-option label="乙班" value="乙" />
|
||||
<el-option label="丙班" value="丙" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<div style="text-align:right;padding-top:4px">
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="submitForm">
|
||||
新增录入(同步创建计划)
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 历史 -->
|
||||
<div class="op-card" style="margin-top:12px">
|
||||
<div class="op-header">
|
||||
<span class="op-title">最近录入记录</span>
|
||||
<el-button size="mini" icon="el-icon-refresh" style="margin-left:auto" @click="loadHistory">刷新</el-button>
|
||||
</div>
|
||||
<el-table v-loading="historyLoading" :data="historyList" size="mini" border style="width:100%">
|
||||
<el-table-column prop="enterCoilNo" label="入场钢卷号" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="currentCoilNo" label="出口钢卷号" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="exitThickness" label="出口厚(mm)" width="90" align="right" />
|
||||
<el-table-column prop="exitWidth" label="出口宽(mm)" width="90" align="right" />
|
||||
<el-table-column prop="exitLength" label="长度(m)" width="80" align="right" />
|
||||
<el-table-column prop="entryWeight" label="入口重(t)" width="80" align="right" />
|
||||
<el-table-column prop="team" label="班组" width="60" align="center" />
|
||||
<el-table-column prop="createTime" label="录入时间" width="150" />
|
||||
</el-table>
|
||||
<pagination v-show="historyTotal > 0" :total="historyTotal"
|
||||
:page.sync="historyQuery.pageNum" :limit.sync="historyQuery.pageSize"
|
||||
@pagination="loadHistory" style="margin-top:6px" />
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧:WMS 钢卷信息 -->
|
||||
<el-col :span="9">
|
||||
<div class="op-card">
|
||||
<div class="op-header"><span class="op-title">WMS 钢卷信息</span></div>
|
||||
<template v-if="coilInfo">
|
||||
<el-descriptions :column="1" size="mini" border style="margin-top:8px">
|
||||
<el-descriptions-item label="入场钢卷号">{{ coilInfo.enterCoilNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="当前钢卷号">{{ coilInfo.currentCoilNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="实际厚度">{{ coilInfo.actualThickness }} mm</el-descriptions-item>
|
||||
<el-descriptions-item label="实际宽度">{{ coilInfo.actualWidth }} mm</el-descriptions-item>
|
||||
<el-descriptions-item label="净重">{{ coilInfo.netWeight }} t</el-descriptions-item>
|
||||
<el-descriptions-item label="长度">{{ coilInfo.length }} m</el-descriptions-item>
|
||||
<el-descriptions-item label="质量状态">{{ coilInfo.qualityStatus }}</el-descriptions-item>
|
||||
<el-descriptions-item label="物料类型">{{ coilInfo.materialType }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-button size="mini" type="primary" style="margin-top:8px" @click="applyCoilFill">
|
||||
写入表单
|
||||
</el-button>
|
||||
</template>
|
||||
<div v-else style="text-align:center;color:#aaa;padding:40px 0">
|
||||
输入入场钢卷号后自动查询
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { addCoilWarehouseOperationLog, listCoilWarehouseOperationLog } from '@/api/wms/coilWarehouseOperationLog'
|
||||
import { queryCoilByNo, addDrPlan } from '@/api/wms/drMill'
|
||||
|
||||
export default {
|
||||
name: 'DrNormal',
|
||||
data() {
|
||||
return {
|
||||
form: this.defaultForm(),
|
||||
rules: {
|
||||
enterCoilNo: [{ required: true, message: '入场钢卷号不能为空', trigger: 'blur' }],
|
||||
},
|
||||
submitting: false,
|
||||
coilInfo: null,
|
||||
historyLoading: false,
|
||||
historyList: [],
|
||||
historyTotal: 0,
|
||||
historyQuery: { pageNum: 1, pageSize: 10, actionType: 504 },
|
||||
}
|
||||
},
|
||||
created() { this.loadHistory() },
|
||||
methods: {
|
||||
defaultForm() {
|
||||
return {
|
||||
enterCoilNo: '', currentCoilNo: '',
|
||||
exitThickness: undefined, exitWidth: undefined, exitLength: undefined,
|
||||
entryWeight: undefined, exitWeight: undefined,
|
||||
processCode: '', team: undefined, remark: '',
|
||||
actionType: 504,
|
||||
}
|
||||
},
|
||||
onEnterCoilInput() {
|
||||
const v = (this.form.enterCoilNo || '').trim()
|
||||
if (!v) return
|
||||
queryCoilByNo(v).then(res => {
|
||||
this.coilInfo = res.data || null
|
||||
}).catch(() => { this.coilInfo = null })
|
||||
},
|
||||
clearCoilInfo() { this.coilInfo = null },
|
||||
applyCoilFill() {
|
||||
if (!this.coilInfo) return
|
||||
if (this.coilInfo.actualThickness) this.form.exitThickness = parseFloat(this.coilInfo.actualThickness)
|
||||
if (this.coilInfo.actualWidth) this.form.exitWidth = parseFloat(this.coilInfo.actualWidth)
|
||||
if (this.coilInfo.netWeight) this.form.entryWeight = parseFloat(this.coilInfo.netWeight)
|
||||
if (this.coilInfo.length) this.form.exitLength = parseFloat(this.coilInfo.length)
|
||||
this.$message.success('钢卷数据已写入表单')
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
this.submitting = true
|
||||
addCoilWarehouseOperationLog({ ...this.form }).then(() => {
|
||||
// 同步创建双机架生产计划
|
||||
return addDrPlan({
|
||||
inMatNo: this.form.enterCoilNo,
|
||||
enterCoilNo: this.form.enterCoilNo,
|
||||
currentCoilNo: this.form.currentCoilNo,
|
||||
inMatThick: this.coilInfo ? this.coilInfo.actualThickness : undefined,
|
||||
inMatWidth: this.coilInfo ? this.coilInfo.actualWidth : undefined,
|
||||
inMatWeight: this.coilInfo ? this.coilInfo.netWeight : undefined,
|
||||
inMatLength: this.coilInfo ? this.coilInfo.length : undefined,
|
||||
outThick: this.form.exitThickness,
|
||||
remark: this.form.remark,
|
||||
})
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('录入成功,已同步创建双机架计划')
|
||||
this.resetForm()
|
||||
this.loadHistory()
|
||||
}).catch(err => {
|
||||
this.$modal.msgError('操作失败: ' + (err.message || ''))
|
||||
}).finally(() => { this.submitting = false })
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.form = this.defaultForm()
|
||||
this.coilInfo = null
|
||||
this.$nextTick(() => this.$refs.form && this.$refs.form.clearValidate())
|
||||
},
|
||||
loadHistory() {
|
||||
this.historyLoading = true
|
||||
listCoilWarehouseOperationLog(this.historyQuery).then(res => {
|
||||
this.historyList = res.rows || []
|
||||
this.historyTotal = res.total || 0
|
||||
}).finally(() => { this.historyLoading = false })
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.acid-op-page { background: #f5f7fa; }
|
||||
.op-card { background: #fff; border: 1px solid #e4e7ed; border-radius: 4px; padding: 16px; }
|
||||
.op-header { display: flex; align-items: center; margin-bottom: 16px; padding-bottom: 10px; border-bottom: 2px solid #409eff; }
|
||||
.op-title { font-size: 15px; font-weight: 600; color: #303133; }
|
||||
</style>
|
||||
231
klp-ui/src/views/wms/coil/do/dr-repair.vue
Normal file
231
klp-ui/src/views/wms/coil/do/dr-repair.vue
Normal file
@@ -0,0 +1,231 @@
|
||||
<template>
|
||||
<div class="app-container acid-op-page">
|
||||
<el-row :gutter="16">
|
||||
|
||||
<el-col :span="15">
|
||||
<div class="op-card">
|
||||
<div class="op-header">
|
||||
<span class="op-title">双机架修复录入</span>
|
||||
<el-tag size="mini" type="warning" style="margin-left:8px">actionType = 524</el-tag>
|
||||
</div>
|
||||
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="110px" size="small">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="入场钢卷号" prop="enterCoilNo">
|
||||
<el-input v-model="form.enterCoilNo" placeholder="回车自动查询"
|
||||
clearable @keyup.enter.native="onEnterCoilInput" @blur="onEnterCoilInput" @clear="clearCoilInfo" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="出口钢卷号">
|
||||
<el-input v-model="form.currentCoilNo" placeholder="请输入出口钢卷号" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left" style="margin:8px 0 12px">修复参数</el-divider>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="修复后厚度(mm)">
|
||||
<el-input-number v-model="form.exitThickness" :precision="3" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="修复后宽度(mm)">
|
||||
<el-input-number v-model="form.exitWidth" :precision="1" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="修复后长度(m)">
|
||||
<el-input-number v-model="form.exitLength" :precision="1" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="入口重量(t)">
|
||||
<el-input-number v-model="form.entryWeight" :precision="3" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="修复后重量(t)">
|
||||
<el-input-number v-model="form.exitWeight" :precision="3" :min="0"
|
||||
:controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="班组">
|
||||
<el-select v-model="form.team" placeholder="请选择" style="width:100%" clearable>
|
||||
<el-option label="甲班" value="甲" />
|
||||
<el-option label="乙班" value="乙" />
|
||||
<el-option label="丙班" value="丙" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<div style="text-align:right;padding-top:4px">
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button type="warning" :loading="submitting" @click="submitForm">
|
||||
新增修复录入(同步创建计划)
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="op-card" style="margin-top:12px">
|
||||
<div class="op-header">
|
||||
<span class="op-title">最近修复记录</span>
|
||||
<el-button size="mini" icon="el-icon-refresh" style="margin-left:auto" @click="loadHistory">刷新</el-button>
|
||||
</div>
|
||||
<el-table v-loading="historyLoading" :data="historyList" size="mini" border style="width:100%">
|
||||
<el-table-column prop="enterCoilNo" label="入场钢卷号" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="currentCoilNo" label="出口钢卷号" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="exitThickness" label="修复后厚(mm)" width="95" align="right" />
|
||||
<el-table-column prop="exitWidth" label="修复后宽(mm)" width="95" align="right" />
|
||||
<el-table-column prop="exitLength" label="长度(m)" width="80" align="right" />
|
||||
<el-table-column prop="team" label="班组" width="60" align="center" />
|
||||
<el-table-column prop="createTime" label="录入时间" width="150" />
|
||||
</el-table>
|
||||
<pagination v-show="historyTotal > 0" :total="historyTotal"
|
||||
:page.sync="historyQuery.pageNum" :limit.sync="historyQuery.pageSize"
|
||||
@pagination="loadHistory" style="margin-top:6px" />
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="9">
|
||||
<div class="op-card">
|
||||
<div class="op-header"><span class="op-title">WMS 钢卷信息</span></div>
|
||||
<template v-if="coilInfo">
|
||||
<el-descriptions :column="1" size="mini" border style="margin-top:8px">
|
||||
<el-descriptions-item label="入场钢卷号">{{ coilInfo.enterCoilNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="当前钢卷号">{{ coilInfo.currentCoilNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="实际厚度">{{ coilInfo.actualThickness }} mm</el-descriptions-item>
|
||||
<el-descriptions-item label="实际宽度">{{ coilInfo.actualWidth }} mm</el-descriptions-item>
|
||||
<el-descriptions-item label="净重">{{ coilInfo.netWeight }} t</el-descriptions-item>
|
||||
<el-descriptions-item label="长度">{{ coilInfo.length }} m</el-descriptions-item>
|
||||
<el-descriptions-item label="质量状态">{{ coilInfo.qualityStatus }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-button size="mini" type="primary" style="margin-top:8px" @click="applyCoilFill">
|
||||
写入表单
|
||||
</el-button>
|
||||
</template>
|
||||
<div v-else style="text-align:center;color:#aaa;padding:40px 0">
|
||||
输入入场钢卷号后自动查询
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { addCoilWarehouseOperationLog, listCoilWarehouseOperationLog } from '@/api/wms/coilWarehouseOperationLog'
|
||||
import { queryCoilByNo, addDrPlan } from '@/api/wms/drMill'
|
||||
|
||||
export default {
|
||||
name: 'DrRepair',
|
||||
data() {
|
||||
return {
|
||||
form: this.defaultForm(),
|
||||
rules: {
|
||||
enterCoilNo: [{ required: true, message: '入场钢卷号不能为空', trigger: 'blur' }],
|
||||
},
|
||||
submitting: false,
|
||||
coilInfo: null,
|
||||
historyLoading: false,
|
||||
historyList: [],
|
||||
historyTotal: 0,
|
||||
historyQuery: { pageNum: 1, pageSize: 10, actionType: 524 },
|
||||
}
|
||||
},
|
||||
created() { this.loadHistory() },
|
||||
methods: {
|
||||
defaultForm() {
|
||||
return {
|
||||
enterCoilNo: '', currentCoilNo: '',
|
||||
exitThickness: undefined, exitWidth: undefined, exitLength: undefined,
|
||||
entryWeight: undefined, exitWeight: undefined,
|
||||
team: undefined, remark: '',
|
||||
actionType: 524,
|
||||
}
|
||||
},
|
||||
onEnterCoilInput() {
|
||||
const v = (this.form.enterCoilNo || '').trim()
|
||||
if (!v) return
|
||||
queryCoilByNo(v).then(res => {
|
||||
this.coilInfo = res.data || null
|
||||
}).catch(() => { this.coilInfo = null })
|
||||
},
|
||||
clearCoilInfo() { this.coilInfo = null },
|
||||
applyCoilFill() {
|
||||
if (!this.coilInfo) return
|
||||
if (this.coilInfo.actualThickness) this.form.exitThickness = parseFloat(this.coilInfo.actualThickness)
|
||||
if (this.coilInfo.actualWidth) this.form.exitWidth = parseFloat(this.coilInfo.actualWidth)
|
||||
if (this.coilInfo.netWeight) this.form.entryWeight = parseFloat(this.coilInfo.netWeight)
|
||||
if (this.coilInfo.length) this.form.exitLength = parseFloat(this.coilInfo.length)
|
||||
this.$message.success('钢卷数据已写入表单')
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
this.submitting = true
|
||||
addCoilWarehouseOperationLog({ ...this.form }).then(() => {
|
||||
return addDrPlan({
|
||||
inMatNo: this.form.enterCoilNo,
|
||||
enterCoilNo: this.form.enterCoilNo,
|
||||
currentCoilNo: this.form.currentCoilNo,
|
||||
inMatThick: this.coilInfo ? this.coilInfo.actualThickness : undefined,
|
||||
inMatWidth: this.coilInfo ? this.coilInfo.actualWidth : undefined,
|
||||
inMatWeight: this.coilInfo ? this.coilInfo.netWeight : undefined,
|
||||
inMatLength: this.coilInfo ? this.coilInfo.length : undefined,
|
||||
outThick: this.form.exitThickness,
|
||||
remark: `[修复] ${this.form.remark || ''}`,
|
||||
})
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('修复录入成功,已同步创建双机架计划')
|
||||
this.resetForm()
|
||||
this.loadHistory()
|
||||
}).catch(err => {
|
||||
this.$modal.msgError('操作失败: ' + (err.message || ''))
|
||||
}).finally(() => { this.submitting = false })
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.form = this.defaultForm()
|
||||
this.coilInfo = null
|
||||
this.$nextTick(() => this.$refs.form && this.$refs.form.clearValidate())
|
||||
},
|
||||
loadHistory() {
|
||||
this.historyLoading = true
|
||||
listCoilWarehouseOperationLog(this.historyQuery).then(res => {
|
||||
this.historyList = res.rows || []
|
||||
this.historyTotal = res.total || 0
|
||||
}).finally(() => { this.historyLoading = false })
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.acid-op-page { background: #f5f7fa; }
|
||||
.op-card { background: #fff; border: 1px solid #e4e7ed; border-radius: 4px; padding: 16px; }
|
||||
.op-header { display: flex; align-items: center; margin-bottom: 16px; padding-bottom: 10px; border-bottom: 2px solid #e6a23c; }
|
||||
.op-title { font-size: 15px; font-weight: 600; color: #303133; }
|
||||
</style>
|
||||
@@ -33,6 +33,7 @@
|
||||
{value: '1988150263284953089', label: '镀锌原料库'},
|
||||
{value: '1988150323162836993', label: '镀锌成品库'},
|
||||
{value: '1988150487185289217', label: '镀锌纵剪分条原料库'},
|
||||
{value: '2056545127927787522', label: '镀锌待打包'}
|
||||
],
|
||||
'脱脂工序': [
|
||||
{value: '1988150545175736322', label: '脱脂原料库'},
|
||||
|
||||
213
klp-ui/src/views/wms/coil/panels/DrMatchPanel.vue
Normal file
213
klp-ui/src/views/wms/coil/panels/DrMatchPanel.vue
Normal file
@@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<div class="dr-panel">
|
||||
|
||||
<!-- 计划概览 -->
|
||||
<div class="panel-block">
|
||||
<div class="pb-header">
|
||||
<span class="pb-title">双机架计划</span>
|
||||
<el-tag v-if="plan" size="mini" type="success" style="margin-left:6px">已找到</el-tag>
|
||||
<el-tag v-else-if="loading" size="mini" type="info" style="margin-left:6px">查询中</el-tag>
|
||||
<el-tag v-else size="mini" type="warning" style="margin-left:6px">未找到</el-tag>
|
||||
</div>
|
||||
|
||||
<template v-if="plan">
|
||||
<div class="plan-grid">
|
||||
<div class="pg-item">
|
||||
<span class="pg-label">计划号</span>
|
||||
<span class="pg-value plan-no">{{ plan.planNo }}</span>
|
||||
</div>
|
||||
<div class="pg-item">
|
||||
<span class="pg-label">合金牌号</span>
|
||||
<span class="pg-value">{{ plan.alloyNo || '—' }}</span>
|
||||
</div>
|
||||
<div class="pg-item">
|
||||
<span class="pg-label">采料厚度</span>
|
||||
<span class="pg-value">{{ plan.inMatThick != null ? plan.inMatThick + ' mm' : '—' }}</span>
|
||||
</div>
|
||||
<div class="pg-item">
|
||||
<span class="pg-label">成品厚度</span>
|
||||
<span class="pg-value accent">{{ plan.outThick != null ? plan.outThick + ' mm' : '—' }}</span>
|
||||
</div>
|
||||
<div class="pg-item">
|
||||
<span class="pg-label">采料宽度</span>
|
||||
<span class="pg-value">{{ plan.inMatWidth != null ? plan.inMatWidth + ' mm' : '—' }}</span>
|
||||
</div>
|
||||
<div class="pg-item">
|
||||
<span class="pg-label">采料重量</span>
|
||||
<span class="pg-value">{{ plan.inMatWeight != null ? plan.inMatWeight + ' t' : '—' }}</span>
|
||||
</div>
|
||||
<div class="pg-item">
|
||||
<span class="pg-label">采料长度</span>
|
||||
<span class="pg-value">{{ plan.inMatLength != null ? plan.inMatLength + ' m' : '—' }}</span>
|
||||
</div>
|
||||
<div class="pg-item">
|
||||
<span class="pg-label">绑定方案</span>
|
||||
<span class="pg-value">{{ plan.recipeNo || '未绑定' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 写入整条计划数据 -->
|
||||
<el-button type="primary" size="small" style="width:100%;margin-top:10px"
|
||||
icon="el-icon-download" @click="fillFromPlan">
|
||||
写入计划数据(重量/宽度/长度/厚度)
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<div v-else-if="loading" class="pb-empty"><i class="el-icon-loading" /></div>
|
||||
<div v-else class="pb-empty">未找到关联的双机架计划</div>
|
||||
</div>
|
||||
|
||||
<!-- 道次列表 -->
|
||||
<div class="panel-block" style="margin-top:12px" v-if="plan && passList.length > 0">
|
||||
<div class="pb-header">
|
||||
<span class="pb-title">道次明细</span>
|
||||
<span class="pb-sub">共 {{ passList.length }} 道次 · 点击行快捷写入成品厚度</span>
|
||||
</div>
|
||||
|
||||
<el-table :data="passList" size="mini" border style="width:100%" max-height="300"
|
||||
highlight-current-row @row-click="fillFromPass">
|
||||
<el-table-column label="道次" prop="passNo" width="44" align="center" />
|
||||
<el-table-column label="入口厚(mm)" prop="inThick" width="78" align="right">
|
||||
<template slot-scope="{ row }">{{ row.inThick != null ? row.inThick : '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口厚(mm)" width="78" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<span class="pass-out-thick">{{ row.outThick != null ? row.outThick : '—' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="轧制力(kN)" prop="rollForce" min-width="72" align="right">
|
||||
<template slot-scope="{ row }">{{ row.rollForce != null ? row.rollForce : '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="" width="46" fixed="right" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" size="mini" @click.stop="fillFromPass(row)">写入</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pass-hint">↑ 通常选最后一道次的出口厚度作为成品实测厚度</div>
|
||||
</div>
|
||||
|
||||
<!-- 无道次提示 -->
|
||||
<div class="panel-block" style="margin-top:12px"
|
||||
v-else-if="plan && plan.recipeId && passList.length === 0">
|
||||
<div class="pb-empty">该方案暂无道次数据</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getDrPlanByActionId } from '@/api/wms/drMill'
|
||||
|
||||
export default {
|
||||
name: 'DrMatchPanel',
|
||||
props: {
|
||||
actionId: { type: [String, Number], default: null }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
plan: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
passList() {
|
||||
return (this.plan && this.plan.passList) || []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
actionId(val) {
|
||||
if (val) this.loadPlan(val)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.actionId) this.loadPlan(this.actionId)
|
||||
},
|
||||
methods: {
|
||||
loadPlan(actionId) {
|
||||
this.plan = null
|
||||
this.loading = true
|
||||
getDrPlanByActionId(actionId)
|
||||
.then(res => { this.plan = res.data || null })
|
||||
.catch(() => {})
|
||||
.finally(() => { this.loading = false })
|
||||
},
|
||||
|
||||
/** 写入计划整体数据:重量/宽度/长度/成品厚度 */
|
||||
fillFromPlan() {
|
||||
const p = this.plan
|
||||
this.$emit('fill', {
|
||||
outThick: p.outThick,
|
||||
inMatWidth: p.inMatWidth,
|
||||
inMatWeight: p.inMatWeight,
|
||||
inMatLength: p.inMatLength,
|
||||
})
|
||||
this.$message.success('已写入计划数据')
|
||||
},
|
||||
|
||||
/** 写入某道次的出口厚度作为成品厚度 */
|
||||
fillFromPass(pass) {
|
||||
this.$emit('fill', {
|
||||
outThick: pass.outThick,
|
||||
inMatWidth: this.plan && this.plan.inMatWidth,
|
||||
inMatWeight: this.plan && this.plan.inMatWeight,
|
||||
inMatLength: this.plan && this.plan.inMatLength,
|
||||
})
|
||||
this.$message.success(`已写入第 ${pass.passNo} 道次厚度`)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dr-panel { font-size: 13px; }
|
||||
|
||||
.panel-block {
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.pb-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
}
|
||||
.pb-title { font-weight: 600; color: #303133; font-size: 13px; }
|
||||
.pb-sub { font-size: 11px; color: #909399; margin-left: 8px; }
|
||||
|
||||
.plan-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 6px 12px;
|
||||
}
|
||||
.pg-item { display: flex; flex-direction: column; }
|
||||
.pg-label { font-size: 11px; color: #909399; }
|
||||
.pg-value { font-size: 13px; color: #303133; font-weight: 500; }
|
||||
.pg-value.accent { color: #409eff; }
|
||||
.plan-no { font-family: 'Courier New', monospace; font-size: 12px; color: #606266; }
|
||||
|
||||
.pb-empty {
|
||||
text-align: center;
|
||||
color: #c0c4cc;
|
||||
padding: 20px 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.pass-out-thick {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-weight: 600;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.pass-hint {
|
||||
font-size: 11px;
|
||||
color: #909399;
|
||||
margin-top: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -680,7 +680,7 @@ export default {
|
||||
}))
|
||||
};
|
||||
|
||||
const response = await splitMaterialCoil(splitData);
|
||||
const response = await splitMaterialCoil({ ...splitData, actionId: this.actionId });
|
||||
if (response.code === 200) {
|
||||
this.$message.success('分条保存成功');
|
||||
|
||||
@@ -698,9 +698,9 @@ export default {
|
||||
}));
|
||||
|
||||
// 如果是从待操作列表进来的,标记操作为完成
|
||||
if (this.actionId) {
|
||||
await completeAction(this.actionId, response.msg);
|
||||
}
|
||||
// if (this.actionId) {
|
||||
// await completeAction(this.actionId, response.msg);
|
||||
// }
|
||||
|
||||
// 延迟返回,让用户看到成功提示
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -26,9 +26,10 @@
|
||||
|
||||
<!-- 主内容区 - 左右布局 -->
|
||||
<div class="content-wrapper">
|
||||
<!-- 左侧:L2 匹配面板 -->
|
||||
<!-- 左侧:快捷写入面板(DR操作用双机架计划面板,其他用L2匹配) -->
|
||||
<div>
|
||||
<l2-match-panel :hot-coil-id="l2HotCoilId" @fill="applyL2Fill" />
|
||||
<dr-match-panel v-if="isDrAction" :action-id="actionId" @fill="applyDrFill" />
|
||||
<l2-match-panel v-else :hot-coil-id="l2HotCoilId" @fill="applyL2Fill" />
|
||||
</div>
|
||||
<!-- 右侧:更新表单 -->
|
||||
<div>
|
||||
@@ -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)
|
||||
@@ -686,7 +713,7 @@ export default {
|
||||
abnormals: this.abnormals,
|
||||
};
|
||||
|
||||
const response = await updateMaterialCoil(updateData);
|
||||
const response = await updateMaterialCoil({ ...updateData, actionId: this.actionId });
|
||||
|
||||
// 更新完成后如果选定了合同,需要增加与合同的绑定关系
|
||||
const coilId = response.msg;
|
||||
@@ -701,11 +728,9 @@ export default {
|
||||
this.$message.success('钢卷信息更新成功');
|
||||
|
||||
// 如果是从待操作列表进来的,标记操作为完成
|
||||
if (this.actionId) {
|
||||
await completeAction(this.actionId, response.msg);
|
||||
}
|
||||
|
||||
|
||||
// if (this.actionId) {
|
||||
// await completeAction(this.actionId, response.msg);
|
||||
// }
|
||||
|
||||
// 延迟返回
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
<el-empty description="请先选择发货计划" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-form style="position: sticky; left: 0; top: 0; padding: 10px;" :model="queryParams" ref="queryForm" size="small"
|
||||
:inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form style="position: sticky; left: 0; top: 0; padding: 10px;" :model="queryParams" ref="queryForm"
|
||||
size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="发货单名称" prop="waybillName">
|
||||
<el-input v-model="queryParams.waybillName" placeholder="请输入发货单名称" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
@@ -113,7 +113,8 @@
|
||||
<!-- <el-table-column label="负责人电话" align="center" prop="principalPhone" width="100" /> -->
|
||||
<el-table-column label="完成状态" align="center" prop="status" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.status" placeholder="请选择完成状态" @change="handleStatusChange(scope.row)">
|
||||
<el-select v-model="scope.row.status" placeholder="请选择完成状态"
|
||||
@change="handleStatusChange(scope.row)">
|
||||
<el-option label="已发货" :value="1" />
|
||||
<el-option label="未发货" :value="0" />
|
||||
<el-option label="已打印" :value="2" />
|
||||
@@ -140,7 +141,8 @@
|
||||
</template>
|
||||
<template slot="panelB">
|
||||
<div style="height: 100%; overflow: auto;">
|
||||
<DeliveryWaybillDetail v-if="canEdit" ref="detailTable" :waybillId="waybillId" :coilList="coilList" :orderId="orderId" />
|
||||
<DeliveryWaybillDetail v-if="canEdit" ref="detailTable" :waybillId="waybillId" :coilList="coilList"
|
||||
:orderId="orderId" />
|
||||
<el-empty v-else description="已发货,不可修改,点击打印查看详情" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -190,8 +192,10 @@
|
||||
|
||||
<!-- 订单选择对话框 -->
|
||||
<el-dialog title="选择订单" :visible.sync="orderDialogVisible" width="800px" append-to-body>
|
||||
<el-input @change="loadOrderList" v-model="orderQuery" placeholder="输入关键词搜索" style="margin-bottom: 10px;" @input="handleOrderSearch" />
|
||||
<el-table v-loading="orderLoading" :data="orderList" max-height="500px" style="width: 100%" @row-click="handleOrderSelect">
|
||||
<el-input @change="loadOrderList" v-model="orderQuery" placeholder="输入关键词搜索" style="margin-bottom: 10px;"
|
||||
@input="handleOrderSearch" />
|
||||
<el-table v-loading="orderLoading" :data="orderList" max-height="500px" style="width: 100%"
|
||||
@row-click="handleOrderSelect">
|
||||
<el-table-column prop="orderCode" label="订单编号" />
|
||||
<el-table-column prop="companyName" label="客户公司" />
|
||||
<el-table-column prop="salesman" label="销售员" />
|
||||
@@ -642,18 +646,24 @@ export default {
|
||||
handlePrint(row, printType) {
|
||||
this.loading = true;
|
||||
this.printType = printType || 0;
|
||||
updateDeliveryWaybill({
|
||||
waybillId: row.waybillId,
|
||||
status: 2
|
||||
}).then(() => {
|
||||
row.status = 2;
|
||||
});
|
||||
// 获取发货单明细
|
||||
listDeliveryWaybillDetail({
|
||||
waybillId: row.waybillId,
|
||||
pageNum: 1,
|
||||
pageSize: 1000 // 获取所有明细
|
||||
}).then(response => {
|
||||
// 该发货单不能是空的
|
||||
if (response.rows.length === 0) {
|
||||
this.$modal.msgError("发货单为空不能打印");
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
updateDeliveryWaybill({
|
||||
waybillId: row.waybillId,
|
||||
status: 2
|
||||
}).then(() => {
|
||||
row.status = 2;
|
||||
});
|
||||
// 处理字段映射,确保与wayBill组件使用的字段名一致
|
||||
this.currentWaybillDetails = response.rows.map(item => ({
|
||||
coilId: item.coilId,
|
||||
|
||||
385
klp-ui/src/views/wms/mill/dr-plan.vue
Normal file
385
klp-ui/src/views/wms/mill/dr-plan.vue
Normal file
@@ -0,0 +1,385 @@
|
||||
<template>
|
||||
<div class="plan-page">
|
||||
|
||||
<!-- 上方:轧制队列 -->
|
||||
<div class="queue-section">
|
||||
<div class="section-header"><span>双机架轧制队列</span></div>
|
||||
<el-table :data="planList" border size="mini" class="queue-table"
|
||||
:row-class-name="queueRowClass"
|
||||
@current-change="handleQueueSelect"
|
||||
highlight-current-row
|
||||
height="calc(50vh - 120px)">
|
||||
<el-table-column label="序号" prop="sortNo" width="50" align="center" fixed />
|
||||
<el-table-column label="入场钢卷号" prop="enterCoilNo" width="115" />
|
||||
<el-table-column label="当前钢卷号" prop="currentCoilNo" width="115" />
|
||||
<el-table-column label="钢卷编号" prop="inMatNo" width="110" />
|
||||
<el-table-column label="合金牌号" prop="alloyNo" width="90" />
|
||||
<el-table-column label="采料厚度(mm)" prop="inMatThick" width="105" align="right" />
|
||||
<el-table-column label="成品厚度(mm)" prop="outThick" width="105" align="right" />
|
||||
<el-table-column label="采料宽度(mm)" prop="inMatWidth" width="105" align="right" />
|
||||
<el-table-column label="采料重量(t)" prop="inMatWeight" width="100" align="right" />
|
||||
<el-table-column label="道次数" prop="passCount" width="65" align="center" />
|
||||
<el-table-column label="生产状态" prop="prodStatus" width="85" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<span :class="prodStatusClass(row.prodStatus)">{{ prodStatusLabel(row.prodStatus) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="工艺方案" prop="recipeNo" min-width="100" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 下方 -->
|
||||
<div class="bottom-section">
|
||||
|
||||
<!-- 左侧:绑定工艺 -->
|
||||
<div class="pass-panel">
|
||||
<template v-if="!selectedPlan">
|
||||
<div class="section-header"><span>轧制工艺</span></div>
|
||||
<div class="pass-empty">请在上方选择一条计划</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="selectedPlan.recipeId && !passEditMode">
|
||||
<div class="section-header">
|
||||
<span>轧制工艺</span>
|
||||
<div style="display:flex;align-items:center;gap:8px">
|
||||
<span class="recipe-tag">{{ selectedPlan.recipeNo }}</span>
|
||||
<el-button size="mini" icon="el-icon-edit" @click="enterEditMode">修改绑定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="passList" border size="mini" class="pass-table"
|
||||
:row-class-name="passRowClass" height="calc(50vh - 160px)">
|
||||
<el-table-column label="道次" prop="passNo" width="45" align="center" fixed />
|
||||
<el-table-column label="入口厚(mm)" prop="inThick" width="90" align="right" />
|
||||
<el-table-column label="出口厚(mm)" prop="outThick" width="90" align="right" />
|
||||
<el-table-column label="轧制力(kN)" prop="rollForce" width="85" align="right" />
|
||||
<el-table-column label="入口张力(kN)" prop="inTension" width="90" align="right" />
|
||||
<el-table-column label="出口张力(kN)" prop="outTension" width="90" align="right" />
|
||||
<el-table-column label="最高速度" prop="maxSpeed" width="80" align="right" />
|
||||
<el-table-column label="压下量(mm)" prop="reduction" width="85" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.reduction }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总压下量(mm)" prop="totalReduction" width="100" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.totalReduction }}</span></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<template v-else-if="!selectedPlan.recipeId && !passEditMode">
|
||||
<div class="section-header"><span>轧制工艺</span></div>
|
||||
<div class="pass-empty">
|
||||
<span>该计划尚未绑定工艺参数</span>
|
||||
<div style="margin-top:12px">
|
||||
<el-button size="mini" type="primary" icon="el-icon-document-copy" @click="openSelectRecipe">选择已有方案</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:查询 + 操作 -->
|
||||
<div class="op-panel">
|
||||
<div class="section-header"><span>条件查询</span></div>
|
||||
<div class="query-form">
|
||||
<el-form size="mini" label-width="72px">
|
||||
<el-form-item label="钢卷号">
|
||||
<el-input v-model="query.inMatNo" clearable placeholder="入场/当前钢卷号" />
|
||||
</el-form-item>
|
||||
<el-form-item label=" " label-width="72px">
|
||||
<el-checkbox v-model="query.hideFinished">不显示已完成</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item label=" " label-width="72px">
|
||||
<el-button size="mini" type="primary" icon="el-icon-search" @click="loadList">查询</el-button>
|
||||
<el-button size="mini" icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="section-header" style="margin-top:8px"><span>队列操作</span></div>
|
||||
<div class="op-buttons">
|
||||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="handleAdd">新增计划</el-button>
|
||||
<el-button size="mini" icon="el-icon-edit" :disabled="!selectedPlan" @click="handleEdit">修改</el-button>
|
||||
<el-button size="mini" icon="el-icon-document" :disabled="!selectedPlan" @click="handleFinish">完成</el-button>
|
||||
<el-button size="mini" type="danger" icon="el-icon-delete" :disabled="!selectedPlan" @click="handleDelete">删除</el-button>
|
||||
<el-button size="mini" icon="el-icon-top" :disabled="!selectedPlan" @click="handleMoveUp">Up 上移</el-button>
|
||||
<el-button size="mini" icon="el-icon-bottom" :disabled="!selectedPlan" @click="handleMoveDown">Down 下移</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增/修改对话框 -->
|
||||
<el-dialog :title="planDialogTitle" :visible.sync="planDialogVisible" width="680px"
|
||||
:close-on-click-modal="false" append-to-body>
|
||||
<el-form :model="form" :rules="rules" ref="formRef" size="mini" label-width="100px">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="入场钢卷号" prop="enterCoilNo">
|
||||
<el-input v-model="form.enterCoilNo"
|
||||
@keyup.enter.native="onCoilNoInput" @blur="onCoilNoInput" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="当前钢卷号">
|
||||
<el-input v-model="form.currentCoilNo" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="合金牌号" prop="alloyNo">
|
||||
<el-input v-model="form.alloyNo" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工艺方案">
|
||||
<el-select v-model="form.recipeId" filterable clearable
|
||||
placeholder="可后续在下方绑定" style="width:100%" @change="onRecipeChange">
|
||||
<el-option v-for="r in recipeOptions" :key="r.recipeId"
|
||||
:label="`${r.recipeNo}(${r.alloyNo})`" :value="r.recipeId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料厚度">
|
||||
<el-input v-model="form.inMatThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="成品厚度">
|
||||
<el-input v-model="form.outThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料宽度">
|
||||
<el-input v-model="form.inMatWidth"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料重量">
|
||||
<el-input v-model="form.inMatWeight"><template slot="append">t</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采料长度">
|
||||
<el-input v-model="form.inMatLength"><template slot="append">m</template></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.remark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="planDialogVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="handleSave">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 选择方案对话框 -->
|
||||
<el-dialog title="选择工艺方案" :visible.sync="selectRecipeVisible" width="480px"
|
||||
:close-on-click-modal="false" append-to-body>
|
||||
<el-select v-model="selectRecipeId" filterable clearable
|
||||
placeholder="输入方案号或合金号搜索" style="width:100%">
|
||||
<el-option v-for="r in recipeOptions" :key="r.recipeId"
|
||||
:label="`${r.recipeNo}(${r.alloyNo})${r.inThick}→${r.outThick}mm`"
|
||||
:value="r.recipeId" />
|
||||
</el-select>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="selectRecipeVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="confirmSelectRecipe">确定绑定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listDrPlan, addDrPlan, updateDrPlan, delDrPlan, moveUpDrPlan, moveDownDrPlan, finishDrPlan,
|
||||
listDrRecipe, getDrRecipeDetail, queryCoilByNo } from '@/api/wms/drMill'
|
||||
|
||||
const emptyForm = () => ({
|
||||
planId: null, planNo: '', enterCoilNo: '', currentCoilNo: '', inMatNo: '',
|
||||
alloyNo: '', recipeId: null, recipeNo: '',
|
||||
outThick: '', inMatThick: '', inMatWidth: '', inMatLength: '',
|
||||
inMatWeight: '', inMatOd: '', inMatId: '', passCount: 0, remark: ''
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'DrPlan',
|
||||
data() {
|
||||
return {
|
||||
planList: [],
|
||||
selectedPlan: null,
|
||||
passList: [],
|
||||
recipeOptions: [],
|
||||
query: { inMatNo: '', hideFinished: false },
|
||||
passEditMode: false,
|
||||
planDialogVisible: false,
|
||||
isNew: true,
|
||||
form: emptyForm(),
|
||||
rules: {
|
||||
enterCoilNo: [{ required: true, message: '请输入入场钢卷号', trigger: 'blur' }],
|
||||
alloyNo: [{ required: true, message: '请输入合金牌号', trigger: 'blur' }],
|
||||
},
|
||||
selectRecipeVisible: false,
|
||||
selectRecipeId: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
planDialogTitle() { return this.isNew ? '新增双机架计划' : '修改双机架计划' }
|
||||
},
|
||||
mounted() {
|
||||
this.loadList()
|
||||
this.refreshRecipeOptions()
|
||||
},
|
||||
methods: {
|
||||
refreshRecipeOptions() {
|
||||
listDrRecipe({}).then(res => { this.recipeOptions = res.data || [] })
|
||||
},
|
||||
loadList() {
|
||||
const params = { inMatNo: this.query.inMatNo }
|
||||
if (this.query.hideFinished) params.planStatus = '0'
|
||||
listDrPlan(params).then(res => { this.planList = res.data || [] })
|
||||
},
|
||||
resetQuery() {
|
||||
this.query = { inMatNo: '', hideFinished: false }
|
||||
this.loadList()
|
||||
},
|
||||
handleQueueSelect(row) {
|
||||
this.selectedPlan = row
|
||||
this.passList = []
|
||||
if (!row) return
|
||||
if (row.recipeId) {
|
||||
getDrRecipeDetail(row.recipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 入场钢卷号变化 → 查 WMS 自动填入
|
||||
onCoilNoInput() {
|
||||
const v = (this.form.enterCoilNo || '').trim()
|
||||
if (!v) return
|
||||
this.form.inMatNo = v
|
||||
queryCoilByNo(v).then(res => {
|
||||
const c = res.data
|
||||
if (!c) return
|
||||
if (c.actualThickness && !this.form.inMatThick) this.form.inMatThick = c.actualThickness
|
||||
if (c.actualWidth && !this.form.inMatWidth) this.form.inMatWidth = String(c.actualWidth)
|
||||
if (c.netWeight && !this.form.inMatWeight) this.form.inMatWeight = String(c.netWeight)
|
||||
if (c.length && !this.form.inMatLength) this.form.inMatLength = String(c.length)
|
||||
if (c.currentCoilNo && !this.form.currentCoilNo) this.form.currentCoilNo = c.currentCoilNo
|
||||
this.$message.success('已从 WMS 自动填入钢卷数据')
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
openSelectRecipe() {
|
||||
this.selectRecipeId = null
|
||||
this.selectRecipeVisible = true
|
||||
},
|
||||
confirmSelectRecipe() {
|
||||
if (!this.selectRecipeId) { this.$message.warning('请选择方案'); return }
|
||||
const r = this.recipeOptions.find(x => x.recipeId === this.selectRecipeId)
|
||||
updateDrPlan({ ...this.selectedPlan, recipeId: this.selectRecipeId, recipeNo: r ? r.recipeNo : '', passCount: r ? r.passCount : 0 })
|
||||
.then(() => {
|
||||
this.$message.success('方案绑定成功')
|
||||
this.selectRecipeVisible = false
|
||||
this.selectedPlan = { ...this.selectedPlan, recipeId: this.selectRecipeId, recipeNo: r ? r.recipeNo : '' }
|
||||
getDrRecipeDetail(this.selectRecipeId).then(res => {
|
||||
this.passList = (res.data && res.data.passList) || []
|
||||
})
|
||||
this.loadList()
|
||||
})
|
||||
},
|
||||
enterEditMode() { this.openSelectRecipe() },
|
||||
onRecipeChange(recipeId) {
|
||||
if (!recipeId) return
|
||||
const r = this.recipeOptions.find(x => x.recipeId === recipeId)
|
||||
if (r) {
|
||||
if (!this.form.alloyNo) this.form.alloyNo = r.alloyNo
|
||||
if (!this.form.inMatThick) this.form.inMatThick = r.inThick
|
||||
if (!this.form.outThick) this.form.outThick = r.outThick
|
||||
if (!this.form.inMatWidth) this.form.inMatWidth = r.outWidth
|
||||
}
|
||||
},
|
||||
|
||||
handleAdd() { this.isNew = true; this.form = emptyForm(); this.planDialogVisible = true },
|
||||
handleEdit() { this.isNew = false; this.form = { ...this.selectedPlan }; this.planDialogVisible = true },
|
||||
handleSave() {
|
||||
this.$refs.formRef.validate(valid => {
|
||||
if (!valid) return
|
||||
if (this.form.recipeId) {
|
||||
const r = this.recipeOptions.find(x => x.recipeId === this.form.recipeId)
|
||||
if (r) { this.form.recipeNo = r.recipeNo; this.form.passCount = r.passCount }
|
||||
}
|
||||
const api = this.isNew ? addDrPlan : updateDrPlan
|
||||
api(this.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.planDialogVisible = false
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDelete() {
|
||||
this.$confirm(`确定删除该计划?`, '提示', { type: 'warning' }).then(() => {
|
||||
delDrPlan(this.selectedPlan.planId).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.selectedPlan = null; this.passList = []
|
||||
this.loadList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleFinish() {
|
||||
finishDrPlan(this.selectedPlan.planId).then(() => {
|
||||
this.$message.success('计划已完成')
|
||||
this.loadList()
|
||||
})
|
||||
},
|
||||
handleMoveUp() { moveUpDrPlan(this.selectedPlan.planId).then(() => this.loadList()) },
|
||||
handleMoveDown() { moveDownDrPlan(this.selectedPlan.planId).then(() => this.loadList()) },
|
||||
|
||||
queueRowClass({ row }) {
|
||||
if (row.prodStatus === 'Rolling') return 'row-rolling'
|
||||
return ''
|
||||
},
|
||||
passRowClass({ rowIndex }) { return rowIndex % 2 === 0 ? '' : 'alt-row' },
|
||||
prodStatusLabel(s) {
|
||||
return { Idle: '待轧', Rolling: '轧制中', NextCoil: '下一卷', Done: '已完成', Error: '异常' }[s] || s
|
||||
},
|
||||
prodStatusClass(s) {
|
||||
return { Idle: 'status-wait', Rolling: 'status-rolling', Done: 'status-done', Error: 'status-err' }[s] || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.plan-page { display: flex; flex-direction: column; height: calc(100vh - 84px); background: #f0f2f5; padding: 8px 12px; box-sizing: border-box; gap: 8px; }
|
||||
|
||||
.section-header { background: #1c2b3a; color: #ecf0f1; padding: 6px 12px; font-size: 12px; font-weight: 700; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; border-radius: 3px 3px 0 0; }
|
||||
|
||||
.recipe-tag { font-size: 11px; font-weight: 400; color: #a9bcd0; margin-right: 4px; }
|
||||
|
||||
.queue-section { background: #fff; border: 1px solid #dde1e6; border-radius: 3px; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.queue-table {
|
||||
::v-deep .row-rolling td { background: #fef3e2 !important; }
|
||||
::v-deep .el-table__row.current-row td { background: #e8f0fb !important; }
|
||||
}
|
||||
|
||||
.bottom-section { display: flex; flex: 1; gap: 8px; overflow: hidden; }
|
||||
|
||||
.pass-panel { flex: 1; background: #fff; border: 1px solid #dde1e6; border-radius: 3px; display: flex; flex-direction: column; overflow: hidden; }
|
||||
.pass-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: #909399; font-size: 12px; }
|
||||
.pass-table { flex: 1; ::v-deep .el-table__row.alt-row td { background: #f7f9fc !important; } }
|
||||
|
||||
.calc-val { font-family: 'Courier New', monospace; font-weight: 600; color: #1d4e89; }
|
||||
|
||||
.op-panel { width: 260px; flex-shrink: 0; background: #fff; border: 1px solid #dde1e6; border-radius: 3px; display: flex; flex-direction: column; overflow-y: auto; }
|
||||
|
||||
.query-form { padding: 10px 12px 4px; border-bottom: 1px solid #e4e7ed; }
|
||||
|
||||
.op-buttons { padding: 8px 12px; display: flex; flex-direction: column; gap: 6px; .el-button { width: 100%; justify-content: flex-start; } }
|
||||
|
||||
.status-wait { color: #7f8c8d; }
|
||||
.status-rolling { color: #d68910; font-weight: 700; }
|
||||
.status-done { color: #2471a3; }
|
||||
.status-err { color: #c0392b; font-weight: 700; }
|
||||
</style>
|
||||
461
klp-ui/src/views/wms/mill/dr-process.vue
Normal file
461
klp-ui/src/views/wms/mill/dr-process.vue
Normal file
@@ -0,0 +1,461 @@
|
||||
<template>
|
||||
<div class="process-page">
|
||||
|
||||
<!-- 左栏:方案列表 -->
|
||||
<div class="col-panel left-panel">
|
||||
<div class="panel-header">
|
||||
<span>工艺方案</span>
|
||||
<el-button type="primary" size="mini" icon="el-icon-plus" @click="handleAddRecipe">新增</el-button>
|
||||
</div>
|
||||
<div class="search-bar">
|
||||
<el-input v-model="searchKey" placeholder="方案号/合金号" size="mini" clearable
|
||||
prefix-icon="el-icon-search" @input="loadRecipeList" />
|
||||
</div>
|
||||
<div class="item-list">
|
||||
<div v-for="r in recipeList" :key="r.recipeId"
|
||||
:class="['list-item', { active: selectedRecipeId === r.recipeId }]"
|
||||
@click="handleSelectRecipe(r)">
|
||||
<div class="item-main">{{ r.recipeNo }}</div>
|
||||
<div class="item-sub">{{ r.alloyNo }} · {{ r.inThick }}→{{ r.outThick }}mm</div>
|
||||
<div class="item-actions">
|
||||
<span class="action-link" @click.stop="handleEditRecipe(r)">编辑</span>
|
||||
<span class="action-link danger" @click.stop="handleDeleteRecipeFromList(r)">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!recipeList.length" class="empty-tip">暂无方案</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中栏:版本列表 -->
|
||||
<div class="col-panel mid-panel">
|
||||
<div class="panel-header">
|
||||
<span>版本列表</span>
|
||||
<el-button type="primary" size="mini" icon="el-icon-plus"
|
||||
:disabled="!selectedRecipeId" @click="handleAddVersion">新增版本</el-button>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
<div v-for="v in versionList" :key="v.versionId"
|
||||
:class="['list-item', { active: selectedVersionId === v.versionId }]"
|
||||
@click="handleSelectVersion(v)">
|
||||
<div class="item-main">
|
||||
{{ v.versionCode }}
|
||||
<el-tag v-if="v.isActive === 1" size="mini" type="success" style="margin-left:4px">激活</el-tag>
|
||||
<el-tag v-else-if="v.status === '1'" size="mini" type="info" style="margin-left:4px">已发布</el-tag>
|
||||
<el-tag v-else size="mini" style="margin-left:4px">草稿</el-tag>
|
||||
</div>
|
||||
<div class="item-sub">{{ v.remark }}</div>
|
||||
<div class="item-actions">
|
||||
<span v-if="v.isActive !== 1" class="action-link" @click.stop="handleActivate(v)">激活</span>
|
||||
<span class="action-link danger" @click.stop="handleDeleteVersion(v)">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedRecipeId && !versionList.length" class="empty-tip">暂无版本,请新增</div>
|
||||
<div v-if="!selectedRecipeId" class="empty-tip">请先选择方案</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右栏:版本详情 + 道次 -->
|
||||
<div class="right-panel">
|
||||
<div v-if="!versionForm.versionId && !isNewVersion" class="no-select">
|
||||
<i class="el-icon-document"></i>
|
||||
<p>请选择或新建版本</p>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<!-- 版本基本信息 -->
|
||||
<div class="detail-header">
|
||||
<span>{{ isNewVersion ? '新建版本' : versionForm.versionCode }}</span>
|
||||
<div class="btn-group">
|
||||
<el-button size="mini" type="primary" icon="el-icon-check" @click="handleSaveVersion">保存</el-button>
|
||||
<el-button size="mini" icon="el-icon-refresh" @click="handleResetVersion">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-form :model="versionForm" ref="versionFormRef" size="mini" label-width="76px"
|
||||
class="version-form" :rules="versionRules">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="5">
|
||||
<el-form-item label="版本号" prop="versionCode">
|
||||
<el-input v-model="versionForm.versionCode" placeholder="如 V1.0" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="versionForm.status" style="width:100%">
|
||||
<el-option label="草稿" value="0" />
|
||||
<el-option label="已发布" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="versionForm.remark" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<!-- 道次参数 -->
|
||||
<div class="pass-section">
|
||||
<div class="pass-header">
|
||||
<span>道次参数</span>
|
||||
<div class="btn-group">
|
||||
<el-button size="mini" icon="el-icon-plus" @click="addPass">增加道次</el-button>
|
||||
<el-button size="mini" icon="el-icon-minus" @click="removeLastPass" :disabled="!passList.length">删除末道</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="passList" border size="mini" class="pass-table"
|
||||
:row-class-name="passRowClass" height="calc(100vh - 310px)">
|
||||
<el-table-column label="道次" prop="passNo" width="50" align="center" fixed>
|
||||
<template slot-scope="{ row }"><b>{{ row.passNo }}</b></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口厚度(mm)" width="100" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.inThick" size="mini" @blur="calcPass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口厚度(mm)" width="100" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.outThick" size="mini" @blur="calcPass(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="宽度(mm)" width="90" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.width" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="轧制力(kN)" width="90" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.rollForce" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口张力(kN)" width="95" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.inTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口张力(kN)" width="95" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.outTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最高速度(m/min)" width="110" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.maxSpeed" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入口单位张力" width="100" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.inUnitTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口单位张力" width="100" align="right">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.outUnitTension" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="压下量(mm)" width="90" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.reduction }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总压下量(mm)" width="100" align="right">
|
||||
<template slot-scope="{ row }"><span class="calc-val">{{ row.totalReduction }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" min-width="100">
|
||||
<template slot-scope="{ row }"><el-input v-model="row.remark" size="mini" /></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑方案对话框 -->
|
||||
<el-dialog :title="recipeDialogTitle" :visible.sync="recipeDialogVisible" width="520px" append-to-body>
|
||||
<el-form :model="recipeForm" :rules="recipeRules" ref="recipeFormRef" size="small" label-width="88px">
|
||||
<el-form-item label="方案记录号" prop="recipeNo">
|
||||
<el-input v-model="recipeForm.recipeNo" :disabled="!!recipeForm.recipeId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合金号" prop="alloyNo">
|
||||
<el-input v-model="recipeForm.alloyNo" />
|
||||
</el-form-item>
|
||||
<el-form-item label="原料厚度">
|
||||
<el-input v-model="recipeForm.inThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="成品厚度">
|
||||
<el-input v-model="recipeForm.outThick"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="成品宽度">
|
||||
<el-input v-model="recipeForm.outWidth"><template slot="append">mm</template></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="recipeDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitRecipe">确定</el-button>
|
||||
<el-button v-if="recipeForm.recipeId" type="danger" @click="handleDeleteRecipe">删除</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listDrRecipe, addDrRecipe, updateDrRecipe, delDrRecipe,
|
||||
listDrRecipeVersions, getDrRecipeVersionDetail,
|
||||
addDrRecipeVersion, updateDrRecipeVersion,
|
||||
activateDrRecipeVersion, delDrRecipeVersion
|
||||
} from '@/api/wms/drMill'
|
||||
|
||||
const emptyPass = (no) => ({
|
||||
passNo: no, inThick: '', outThick: '', width: '',
|
||||
rollForce: '', inTension: '', outTension: '',
|
||||
maxSpeed: '', inUnitTension: '', outUnitTension: '',
|
||||
reduction: '', totalReduction: '', remark: ''
|
||||
})
|
||||
|
||||
const emptyVersionForm = () => ({
|
||||
versionId: null, recipeId: null, versionCode: '', status: '0', remark: ''
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'DrProcess',
|
||||
data() {
|
||||
return {
|
||||
// 方案
|
||||
searchKey: '',
|
||||
recipeList: [],
|
||||
selectedRecipeId: null,
|
||||
recipeDialogVisible: false,
|
||||
recipeDialogTitle: '新增工艺方案',
|
||||
recipeForm: {},
|
||||
recipeRules: {
|
||||
recipeNo: [{ required: true, message: '请输入方案记录号', trigger: 'blur' }],
|
||||
alloyNo: [{ required: true, message: '请输入合金号', trigger: 'blur' }],
|
||||
},
|
||||
// 版本
|
||||
versionList: [],
|
||||
selectedVersionId: null,
|
||||
isNewVersion: false,
|
||||
versionForm: emptyVersionForm(),
|
||||
versionRules: {
|
||||
versionCode: [{ required: true, message: '请输入版本号', trigger: 'blur' }],
|
||||
},
|
||||
// 道次
|
||||
passList: [],
|
||||
}
|
||||
},
|
||||
mounted() { this.loadRecipeList() },
|
||||
methods: {
|
||||
// ── 方案 ──────────────────────────────────────────────────
|
||||
loadRecipeList() {
|
||||
listDrRecipe({ recipeNo: this.searchKey, alloyNo: this.searchKey }).then(res => {
|
||||
this.recipeList = res.data || []
|
||||
})
|
||||
},
|
||||
handleSelectRecipe(r) {
|
||||
this.selectedRecipeId = r.recipeId
|
||||
this.isNewVersion = false
|
||||
this.selectedVersionId = null
|
||||
this.versionForm = emptyVersionForm()
|
||||
this.passList = []
|
||||
this.loadVersionList(r.recipeId)
|
||||
},
|
||||
handleAddRecipe() {
|
||||
this.recipeForm = { recipeNo: '', alloyNo: '', inThick: '', outThick: '', outWidth: '', status: '0' }
|
||||
this.recipeDialogTitle = '新增工艺方案'
|
||||
this.recipeDialogVisible = true
|
||||
},
|
||||
handleEditRecipe(r) {
|
||||
this.recipeForm = { ...r }
|
||||
this.recipeDialogTitle = '编辑工艺方案'
|
||||
this.recipeDialogVisible = true
|
||||
},
|
||||
submitRecipe() {
|
||||
this.$refs.recipeFormRef.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.recipeForm.recipeId ? updateDrRecipe : addDrRecipe
|
||||
api(this.recipeForm).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.recipeDialogVisible = false
|
||||
this.loadRecipeList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteRecipe() {
|
||||
this.$confirm('确定删除该方案及所有版本?', '提示', { type: 'warning' }).then(() => {
|
||||
delDrRecipe([this.recipeForm.recipeId]).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.recipeDialogVisible = false
|
||||
this.selectedRecipeId = null
|
||||
this.versionList = []
|
||||
this.versionForm = emptyVersionForm()
|
||||
this.passList = []
|
||||
this.loadRecipeList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteRecipeFromList(r) {
|
||||
this.$confirm(`确定删除方案「${r.recipeNo}」及其所有版本?`, '提示', { type: 'warning' }).then(() => {
|
||||
delDrRecipe([r.recipeId]).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
if (this.selectedRecipeId === r.recipeId) {
|
||||
this.selectedRecipeId = null
|
||||
this.versionList = []
|
||||
this.versionForm = emptyVersionForm()
|
||||
this.passList = []
|
||||
}
|
||||
this.loadRecipeList()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// ── 版本 ──────────────────────────────────────────────────
|
||||
loadVersionList(recipeId) {
|
||||
listDrRecipeVersions(recipeId).then(res => {
|
||||
this.versionList = res.data || []
|
||||
})
|
||||
},
|
||||
handleSelectVersion(v) {
|
||||
this.selectedVersionId = v.versionId
|
||||
this.isNewVersion = false
|
||||
getDrRecipeVersionDetail(v.versionId).then(res => {
|
||||
this.versionForm = { ...res.data }
|
||||
this.passList = (res.data.passList || []).map(p => ({ ...p }))
|
||||
})
|
||||
},
|
||||
handleAddVersion() {
|
||||
this.isNewVersion = true
|
||||
this.selectedVersionId = null
|
||||
this.versionForm = { ...emptyVersionForm(), recipeId: this.selectedRecipeId }
|
||||
this.passList = []
|
||||
},
|
||||
handleSaveVersion() {
|
||||
this.$refs.versionFormRef.validate(valid => {
|
||||
if (!valid) return
|
||||
this.versionForm.passList = this.passList
|
||||
const api = this.isNewVersion ? addDrRecipeVersion : updateDrRecipeVersion
|
||||
api(this.versionForm).then(res => {
|
||||
this.$message.success('保存成功')
|
||||
this.isNewVersion = false
|
||||
if (res.data) this.versionForm.versionId = res.data
|
||||
this.loadVersionList(this.selectedRecipeId)
|
||||
})
|
||||
})
|
||||
},
|
||||
handleResetVersion() {
|
||||
if (this.isNewVersion) {
|
||||
this.versionForm = { ...emptyVersionForm(), recipeId: this.selectedRecipeId }
|
||||
this.passList = []
|
||||
} else {
|
||||
this.handleSelectVersion({ versionId: this.selectedVersionId })
|
||||
}
|
||||
},
|
||||
handleActivate(v) {
|
||||
this.$confirm(`确定激活版本 ${v.versionCode}?`, '提示', { type: 'warning' }).then(() => {
|
||||
activateDrRecipeVersion(v.versionId).then(() => {
|
||||
this.$message.success('激活成功')
|
||||
this.loadVersionList(this.selectedRecipeId)
|
||||
if (this.selectedVersionId === v.versionId) {
|
||||
this.versionForm.isActive = 1
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteVersion(v) {
|
||||
this.$confirm(`确定删除版本 ${v.versionCode}?`, '提示', { type: 'warning' }).then(() => {
|
||||
delDrRecipeVersion(v.versionId).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
if (this.selectedVersionId === v.versionId) {
|
||||
this.selectedVersionId = null
|
||||
this.versionForm = emptyVersionForm()
|
||||
this.passList = []
|
||||
}
|
||||
this.loadVersionList(this.selectedRecipeId)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// ── 道次 ──────────────────────────────────────────────────
|
||||
addPass() { this.passList.push(emptyPass(this.passList.length + 1)) },
|
||||
removeLastPass() { if (this.passList.length) this.passList.pop() },
|
||||
calcPass(row) {
|
||||
const inT = parseFloat(row.inThick) || 0
|
||||
const outT = parseFloat(row.outThick) || 0
|
||||
row.reduction = outT > 0 ? (inT - outT).toFixed(3) : ''
|
||||
const base = parseFloat(this.passList[0] && this.passList[0].inThick) || 0
|
||||
for (const p of this.passList) {
|
||||
const pOut = parseFloat(p.outThick) || 0
|
||||
if (base > 0 && pOut > 0) p.totalReduction = parseFloat((base - pOut).toFixed(3))
|
||||
}
|
||||
},
|
||||
passRowClass({ rowIndex }) { return rowIndex % 2 === 0 ? '' : 'alt-row' }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.process-page {
|
||||
display: flex; height: calc(100vh - 84px); gap: 0;
|
||||
background: #f5f7fa; padding: 10px 12px; box-sizing: border-box;
|
||||
}
|
||||
|
||||
.col-panel {
|
||||
flex-shrink: 0; background: #fff; border: 1px solid #e4e7ed;
|
||||
border-radius: 3px; display: flex; flex-direction: column;
|
||||
margin-right: 8px; overflow: hidden;
|
||||
}
|
||||
.left-panel { width: 200px; }
|
||||
.mid-panel { width: 200px; }
|
||||
|
||||
.panel-header {
|
||||
background: #fff; color: #303133; padding: 7px 10px;
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
font-size: 12px; font-weight: 700; flex-shrink: 0;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.search-bar { padding: 6px 8px; border-bottom: 1px solid #e4e7ed; flex-shrink: 0; }
|
||||
|
||||
.item-list { flex: 1; overflow-y: auto; }
|
||||
|
||||
.list-item {
|
||||
padding: 7px 10px; border-bottom: 1px solid #f5f7fa;
|
||||
cursor: pointer; transition: background .15s;
|
||||
&:hover { background: #f5f7fa; }
|
||||
&.active { background: #ecf5ff; border-left: 3px solid #409eff; }
|
||||
.item-main { font-size: 12px; font-weight: 700; color: #303133; }
|
||||
.item-sub { font-size: 11px; color: #909399; margin-top: 2px; }
|
||||
.item-actions {
|
||||
display: flex; gap: 8px; margin-top: 3px;
|
||||
.action-link { font-size: 11px; color: #409eff; cursor: pointer;
|
||||
&:hover { text-decoration: underline; }
|
||||
&.danger { color: #f56c6c; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-tip { text-align: center; color: #c0c4cc; padding: 24px 0; font-size: 12px; }
|
||||
|
||||
.right-panel {
|
||||
flex: 1; background: #fff; border: 1px solid #e4e7ed;
|
||||
border-radius: 3px; display: flex; flex-direction: column; overflow: hidden;
|
||||
}
|
||||
|
||||
.no-select {
|
||||
flex: 1; display: flex; flex-direction: column; align-items: center;
|
||||
justify-content: center; color: #c0c4cc; font-size: 13px;
|
||||
i { font-size: 48px; margin-bottom: 10px; }
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
background: #fff; color: #303133; padding: 7px 12px;
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
font-size: 12px; font-weight: 700; flex-shrink: 0;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.btn-group { display: flex; gap: 6px; }
|
||||
|
||||
.version-form { padding: 8px 12px 4px; flex-shrink: 0; border-bottom: 1px solid #e4e7ed; }
|
||||
|
||||
.pass-section { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
|
||||
|
||||
.pass-header {
|
||||
padding: 6px 12px; background: #f5f7fa; border-bottom: 1px solid #e4e7ed;
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
font-size: 12px; font-weight: 700; color: #303133; flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pass-table {
|
||||
flex: 1;
|
||||
::v-deep .el-table__row.alt-row td { background: #f5f7fa !important; }
|
||||
::v-deep .el-input__inner { text-align: right; padding: 0 4px !important; }
|
||||
}
|
||||
|
||||
.calc-val { font-family: 'Courier New', monospace; font-weight: 600; color: #409eff; }
|
||||
</style>
|
||||
@@ -65,7 +65,7 @@
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
<span class="search-label">点位名称:</span>
|
||||
<span class="search-label">参数名称:</span>
|
||||
<el-input
|
||||
v-model="filterName"
|
||||
placeholder="请输入"
|
||||
@@ -80,8 +80,13 @@
|
||||
size="mini"
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
@click="openParamDialog()"
|
||||
>新建参数</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
icon="el-icon-setting"
|
||||
@click="openPlanDialog()"
|
||||
>新建方案点位</el-button>
|
||||
>管理点位</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="success"
|
||||
@@ -90,51 +95,24 @@
|
||||
>模板导入</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 方案点位表 -->
|
||||
<!-- 参数平铺表 -->
|
||||
<el-table
|
||||
v-loading="planLoading"
|
||||
:data="filteredPlans"
|
||||
v-loading="planLoading || allParamLoading"
|
||||
:data="filteredFlatRows"
|
||||
size="small"
|
||||
highlight-current-row
|
||||
@current-change="onPlanSelect"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" type="index" align="center" />
|
||||
<el-table-column label="父级名称" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ segLabel(row.segmentType) }} › {{ row.segmentName || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="点位名称" prop="pointName" show-overflow-tooltip />
|
||||
<el-table-column label="点位编码" prop="pointCode" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="right">
|
||||
<el-table-column label="段" width="68" align="center" fixed>
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" size="mini" @click.stop="openPlanDialog(row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" @click.stop="openParamDialog(row)">参数</el-button>
|
||||
<el-button type="text" size="mini" class="btn-danger" @click.stop="removePlan(row)">删除</el-button>
|
||||
<span :class="['seg-chip', 'seg-' + (row._segmentType || '').toLowerCase()]">{{ row._segmentLabel }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 方案参数面板 -->
|
||||
<template v-if="selectedPlan">
|
||||
<div class="param-header">
|
||||
<span>{{ selectedPlan.pointName || selectedPlan.pointCode }} — 参数</span>
|
||||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openParamDialog()">新建参数</el-button>
|
||||
</div>
|
||||
<el-table v-loading="paramLoading" :data="paramList" size="small">
|
||||
<el-table-column label="参数编码" prop="paramCode" width="110" show-overflow-tooltip />
|
||||
<el-table-column label="参数名称" prop="paramName" show-overflow-tooltip />
|
||||
<el-table-column label="实际值ID" prop="actualSrcId" width="140" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.actualSrcId || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="L1设定值ID" prop="presetSrcId" width="140" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.presetSrcId || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="设定值" prop="targetValue" align="right" width="80" />
|
||||
<el-table-column label="最小值" prop="lowerLimit" align="right" width="80" />
|
||||
<el-table-column label="最大值" prop="upperLimit" align="right" width="80" />
|
||||
<el-table-column label="单位" prop="unit" align="center" width="60" />
|
||||
<el-table-column label="更新时间" align="center" width="136">
|
||||
<template slot-scope="{ row }">{{ (row.updateTime || row.createTime || '').substring(0, 16) || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="参数名称" prop="paramName" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column label="编码" prop="paramCode" width="115" show-overflow-tooltip />
|
||||
<el-table-column label="单位" prop="unit" align="center" width="62" />
|
||||
<el-table-column label="设定值" prop="targetValue" align="right" width="82" />
|
||||
<el-table-column label="下限" prop="lowerLimit" align="right" width="72" />
|
||||
<el-table-column label="上限" prop="upperLimit" align="right" width="72" />
|
||||
<el-table-column label="实际状态" align="center" width="90">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="paramAnomalyMap[row.paramCode]" class="anomaly-badge">
|
||||
@@ -146,78 +124,13 @@
|
||||
<span v-else class="no-data-badge">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="right">
|
||||
<el-table-column label="操作" align="right" width="100" fixed="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" size="mini" @click="openParamDialog(null, row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" class="btn-danger" @click="removeParam(row)">删除</el-button>
|
||||
<el-button type="text" size="mini" @click="editParamFromFlat(row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" class="btn-danger" @click="deleteParamFromFlat(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 偏差分析区块 -->
|
||||
<template v-if="planAnomalies.length">
|
||||
<div class="anomaly-section-header">
|
||||
<i class="el-icon-warning" style="color:#E6A23C;margin-right:4px" />
|
||||
实际生产偏差分析
|
||||
<el-tag type="warning" size="mini" effect="plain" style="margin-left:8px">{{ planAnomalies.length }} 项异常</el-tag>
|
||||
<el-button type="text" size="mini" style="margin-left:auto" @click="anomalyExpanded = !anomalyExpanded">
|
||||
{{ anomalyExpanded ? '收起' : '展开' }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-show="anomalyExpanded">
|
||||
<el-table :data="planAnomalies" size="small" border>
|
||||
<el-table-column label="参数" prop="paramName" width="110" show-overflow-tooltip />
|
||||
<el-table-column label="规程设定值" align="right" width="96">
|
||||
<template slot-scope="{ row }">{{ row.storedTarget != null ? row.storedTarget : '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规程最大值" align="right" width="96">
|
||||
<template slot-scope="{ row }">{{ row.storedUpper != null ? row.storedUpper : '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规程最小值" align="right" width="96">
|
||||
<template slot-scope="{ row }">{{ row.storedLower != null ? row.storedLower : '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="实际最大值" align="right" width="96">
|
||||
<template slot-scope="{ row }">
|
||||
<span :class="(row.anomalyType === 'OVER_MAX' || row.anomalyType === 'BOTH') ? 'val-over' : ''">
|
||||
{{ row.actualMax != null ? row.actualMax : '—' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="实际最小值" align="right" width="96">
|
||||
<template slot-scope="{ row }">
|
||||
<span :class="(row.anomalyType === 'UNDER_MIN' || row.anomalyType === 'BOTH') ? 'val-under' : ''">
|
||||
{{ row.actualMin != null ? row.actualMin : '—' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最大偏差" align="right" width="88">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.deviationMax != null" class="val-over">+{{ row.deviationMax }}</span>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最小偏差" align="right" width="88">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.deviationMin != null" class="val-under">{{ row.deviationMin }}</span>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来源钢卷" prop="coilId" show-overflow-tooltip width="120" />
|
||||
<el-table-column label="检测时间" prop="detectedAt" width="140" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ (row.detectedAt || '').substring(0, 16) || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="异常类型" align="center" width="120">
|
||||
<template slot-scope="{ row }">
|
||||
<el-tag v-if="row.anomalyType === 'OVER_MAX' || row.anomalyType === 'BOTH'" size="mini" type="danger" style="margin:1px">超上限</el-tag>
|
||||
<el-tag v-if="row.anomalyType === 'UNDER_MIN' || row.anomalyType === 'BOTH'" size="mini" type="warning" style="margin:1px">低于下限</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 对比图 -->
|
||||
<div ref="anomalyChart" class="anomaly-chart" />
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -361,6 +274,16 @@
|
||||
<!-- 方案参数 dialog -->
|
||||
<el-dialog :title="paramTitle" :visible.sync="paramOpen" width="480px" append-to-body @close="paramForm = {}">
|
||||
<el-form ref="paramFormRef" :model="paramForm" :rules="paramRules" label-width="90px" size="small">
|
||||
<el-form-item v-if="!paramForm.paramId" label="所属点位" prop="planId">
|
||||
<el-select v-model="paramForm.planId" style="width:100%" placeholder="请选择点位">
|
||||
<el-option
|
||||
v-for="plan in planList"
|
||||
:key="plan.planId"
|
||||
:label="segLabel(plan.segmentType) + ' › ' + plan.pointName"
|
||||
:value="plan.planId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="参数编码" prop="paramCode">
|
||||
<el-input v-model="paramForm.paramCode" maxlength="64" />
|
||||
</el-form-item>
|
||||
@@ -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,16 +839,10 @@ 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,
|
||||
planId: planRow ? planRow.planId : undefined,
|
||||
paramCode: undefined,
|
||||
paramName: undefined,
|
||||
targetValue: undefined,
|
||||
@@ -943,6 +855,17 @@ export default {
|
||||
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(() => {})
|
||||
},
|
||||
// ===================== 导入相关方法 =====================
|
||||
/**
|
||||
* 打开导入对话框
|
||||
@@ -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;
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
<muti-select style="width: 200px;" v-model="queryParams.itemManufacturer"
|
||||
:options="dict.type.coil_manufacturer" placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<!-- <el-button type="primary" @click="getList">查询</el-button> -->
|
||||
<el-dropdown split-button type="primary" @click="getList" @command="handleCommand">
|
||||
@@ -99,14 +103,16 @@
|
||||
<el-tab-pane label="产出钢卷" name="output">
|
||||
<coil-table :data="outList" :columns="outputColumns" :loading="loading" height="calc(100vh - 360px)">
|
||||
<template slot="settings">
|
||||
<el-button icon="el-icon-setting" @click="() => {settingVisible = true; activeColumnConfig = 'coil-report-output';}">列设置</el-button>
|
||||
<el-button icon="el-icon-setting"
|
||||
@click="() => { settingVisible = true; activeColumnConfig = 'coil-report-output'; }">列设置</el-button>
|
||||
</template>
|
||||
</coil-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="投入钢卷" name="loss">
|
||||
<coil-table :data="lossList" :columns="lossColumns" :loading="loading" height="calc(100vh - 360px)">
|
||||
<template slot="settings">
|
||||
<el-button icon="el-icon-setting" @click="() => {settingVisible = true; activeColumnConfig = 'coil-report-loss';}">列设置</el-button>
|
||||
<el-button icon="el-icon-setting"
|
||||
@click="() => { settingVisible = true; activeColumnConfig = 'coil-report-loss'; }">列设置</el-button>
|
||||
</template>
|
||||
</coil-table>
|
||||
</el-tab-pane>
|
||||
@@ -147,7 +153,7 @@ export default {
|
||||
ColumnsSetting,
|
||||
TimeRangePicker
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
|
||||
@@ -3,14 +3,8 @@
|
||||
<el-row>
|
||||
<el-form label-width="80px" inline>
|
||||
<el-form-item label="时间范围" prop="timeRange">
|
||||
<time-range-picker
|
||||
v-model="queryParams"
|
||||
start-key="byExportTimeStart"
|
||||
end-key="byExportTimeEnd"
|
||||
:default-start-time="defaultStartTime"
|
||||
:default-end-time="defaultEndTime"
|
||||
@quick-select="handleQuery"
|
||||
/>
|
||||
<time-range-picker v-model="queryParams" start-key="byExportTimeStart" end-key="byExportTimeEnd"
|
||||
:default-start-time="defaultStartTime" :default-end-time="defaultEndTime" @quick-select="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="入场钢卷号" prop="endTime">
|
||||
<el-input style="width: 200px; display: inline-block;" v-model="queryParams.enterCoilNo"
|
||||
@@ -40,6 +34,10 @@
|
||||
<muti-select style="width: 200px;" v-model="queryParams.itemManufacturer"
|
||||
:options="dict.type.coil_manufacturer" placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="endTime">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item prop="endTime">
|
||||
<el-button type="primary" @click="getList">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出</el-button>
|
||||
@@ -93,7 +91,7 @@ export default {
|
||||
CoilTable,
|
||||
TimeRangePicker,
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零,保证格式统一(比如 9 → 09,5 → 05)
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
|
||||
@@ -20,26 +20,32 @@
|
||||
<el-input style="width: 200px;" v-model="queryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位" prop="endTime">
|
||||
<el-form-item label="逻辑库位" prop="warehouseId">
|
||||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位"
|
||||
style="width: 100%; display: inline-block; width: 200px;" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称" prop="endTime">
|
||||
<el-form-item label="产品名称" prop="itemName">
|
||||
<el-input style="width: 200px;" v-model="queryParams.itemName" placeholder="请输入产品名称" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格" prop="endTime">
|
||||
<el-form-item label="规格" prop="itemSpecification">
|
||||
<memo-input style="width: 200px;" v-model="queryParams.itemSpecification" storageKey="coilSpec"
|
||||
placeholder="请选择规格" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="材质" prop="endTime">
|
||||
<el-form-item label="材质" prop="itemMaterial">
|
||||
<muti-select style="width: 200px;" v-model="queryParams.itemMaterial" :options="dict.type.coil_material"
|
||||
placeholder="请选择材质" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="厂家" prop="endTime">
|
||||
<el-form-item label="厂家" prop="itemManufacturer">
|
||||
<muti-select style="width: 200px;" v-model="queryParams.itemManufacturer"
|
||||
:options="dict.type.coil_manufacturer" placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="收货计划" prop="planId">
|
||||
<el-select style="width: 200px;" v-model="queryParams.planId" placeholder="请输入计划名称搜索收货计划" filterable remote
|
||||
:remote-method="remoteMethod">
|
||||
@@ -115,7 +121,7 @@ export default {
|
||||
HierarchicalPivot,
|
||||
CrossTable,
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零,保证格式统一(比如 9 → 09,5 → 05)
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
|
||||
@@ -71,12 +71,19 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dict-type="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<!-- 逻辑库位仅在 team, day, month, year, all 类型时显示 -->
|
||||
<el-form-item v-if="['team', 'day', 'month', 'year', 'all'].includes(reportType)" label="逻辑库位"
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item v-if="['team', 'day', 'month', 'year', 'all'].includes(reportType)" label="逻辑库位"
|
||||
prop="warehouseIds">
|
||||
<el-select v-model="warehouseIds" collapse-tags multiple placeholder="请选择逻辑库位" style="width: 200px;">
|
||||
<el-option v-for="item in warehouseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="逻辑库位" prop="warehouseId">
|
||||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位"
|
||||
style="width: 100%; display: inline-block; width: 200px;" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
@@ -219,7 +226,7 @@ export default {
|
||||
name: 'MergeTemplate',
|
||||
props: {
|
||||
actionType: {
|
||||
type: Number,
|
||||
type: [Number, String],
|
||||
required: true
|
||||
},
|
||||
productionLine: {
|
||||
@@ -246,7 +253,7 @@ export default {
|
||||
ColumnsSetting,
|
||||
TimeRangePicker
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
@@ -466,7 +473,7 @@ export default {
|
||||
this.loading = true;
|
||||
|
||||
// 所有报表类型都使用原始的 listPendingAction 方式获取数据
|
||||
const res = await listPendingAction({ ...this.queryParams, actionType: this.actionType, actionStatus: 2 });
|
||||
const res = await listPendingAction({ ...this.queryParams, actionTypes: this.actionType, actionStatus: 2 });
|
||||
// 获取两层数据
|
||||
const lossIds = res.rows.filter(item => item.coilId).map(item => item.coilId);
|
||||
const lossActionIds = res.rows.filter(item => item.actionId).map(item => item.actionId);
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
<div class="app-container" v-loading="loading">
|
||||
<!-- 对日期的筛选另起一行 -->
|
||||
<div style="margin-bottom: 10px;">
|
||||
<!-- 单选按钮,用于切换视图,可以使用日视图、月视图、年视图、自定义, 默认使用自定义日期 -->
|
||||
<!-- 日视图时选择一天, 月视图时选择一个月, 年视图时选择一年, 自定义时选择自定义时间范围 -->
|
||||
<el-radio-group v-model="viewType" @change="handleViewTypeChange">
|
||||
<el-radio-button label="day">日视图</el-radio-button>
|
||||
<el-radio-button label="month">月视图</el-radio-button>
|
||||
@@ -42,10 +40,14 @@
|
||||
<el-input style="width: 200px;" v-model="queryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<!-- <el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<el-select v-model="warehouseIds" collapse-tags multiple placeholder="请选择逻辑库位" style="width: 200px;">
|
||||
<el-option v-for="item in warehouseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="逻辑库位" prop="warehouseId">
|
||||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位"
|
||||
style="width: 100%; display: inline-block; width: 200px;" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称" prop="itemName">
|
||||
<el-input style="width: 200px;" v-model="queryParams.itemName" placeholder="请输入产品名称" clearable
|
||||
@@ -63,6 +65,10 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dictType="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable multiple />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
||||
@@ -86,7 +92,6 @@
|
||||
<el-descriptions-item label="数量差值">{{ summary.countDiff }}<span v-if="viewType === 'day' && yesterdaySummary.countDiff" style="margin-left: 10px; font-size: 12px; color: #999;">(昨日: {{ yesterdaySummary.countDiff }})</span></el-descriptions-item>
|
||||
<el-descriptions-item label="总重差值">{{ summary.weightDiff }}<span v-if="viewType === 'day' && yesterdaySummary.weightDiff" style="margin-left: 10px; font-size: 12px; color: #999;">(昨日: {{ yesterdaySummary.weightDiff }})</span></el-descriptions-item>
|
||||
<el-descriptions-item label="均重差值">{{ summary.avgWeightDiff }}t<span v-if="viewType === 'day' && yesterdaySummary.avgWeightDiff" style="margin-left: 10px; font-size: 12px; color: #999;">(昨日: {{ yesterdaySummary.avgWeightDiff }}t)</span></el-descriptions-item>
|
||||
<!-- <el-descriptions-item label="合计均重">{{ summary.totalAvgWeight }}t</el-descriptions-item> -->
|
||||
|
||||
<!-- 成品率 -->
|
||||
<el-descriptions-item label="成品率">{{ summary.passRate }}<span v-if="viewType === 'day' && yesterdaySummary.passRate" style="margin-left: 10px; font-size: 12px; color: #999;">(昨日: {{ yesterdaySummary.passRate }})</span></el-descriptions-item>
|
||||
@@ -216,7 +221,7 @@ export default {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
@@ -443,7 +448,7 @@ export default {
|
||||
fetchOutputList({
|
||||
...this.queryParams,
|
||||
...this.baseQueryParams,
|
||||
warehouseIds: this.warehouseIds.join(','),
|
||||
// warehouseIds: this.warehouseIds.join(','),
|
||||
}),
|
||||
]).then(([lossList, outputList]) => {
|
||||
this.lossList = lossList
|
||||
|
||||
@@ -14,10 +14,14 @@
|
||||
<el-input style="width: 200px;" v-model="queryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<!-- <el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<el-select v-model="warehouseIds" collapse-tags multiple placeholder="请选择逻辑库位" style="width: 200px;">
|
||||
<el-option v-for="item in warehouseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="逻辑库位" prop="warehouseId">
|
||||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位"
|
||||
style="width: 100%; display: inline-block; width: 200px;" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称" prop="itemName">
|
||||
<el-input style="width: 200px;" v-model="queryParams.itemName" placeholder="请输入产品名称" clearable
|
||||
@@ -35,6 +39,10 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dict-type="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable multiple />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button> <!-- 统一改为handleQuery -->
|
||||
<el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
||||
@@ -153,6 +161,7 @@ export default {
|
||||
CoilTable,
|
||||
SplitSummary,
|
||||
},
|
||||
dicts: ['coil_quality_status'],
|
||||
props: {
|
||||
actionTypes: {
|
||||
type: Array,
|
||||
@@ -332,7 +341,7 @@ export default {
|
||||
fetchOutputList({
|
||||
...this.queryParams,
|
||||
...this.baseQueryParams,
|
||||
warehouseIds: this.warehouseIds.join(','),
|
||||
// warehouseIds: this.warehouseIds.join(','),
|
||||
}),
|
||||
]).then(([lossList, outputList]) => {
|
||||
this.lossList = lossList
|
||||
|
||||
@@ -40,6 +40,10 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dict-type="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item prop="endTime">
|
||||
<el-button type="primary" @click="getList">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出</el-button>
|
||||
@@ -111,7 +115,7 @@ export default {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
dicts: ['coil_material', 'coil_manufacturer'],
|
||||
dicts: ['coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零,保证格式统一(比如 9 → 09,5 → 05)
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
|
||||
@@ -42,10 +42,14 @@
|
||||
<el-input style="width: 200px;" v-model="queryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<!-- <el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<el-select v-model="warehouseIds" collapse-tags multiple placeholder="请选择逻辑库位" style="width: 200px;">
|
||||
<el-option v-for="item in warehouseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="逻辑库位" prop="warehouseId">
|
||||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位"
|
||||
style="width: 100%; display: inline-block; width: 200px;" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称" prop="itemName">
|
||||
<el-input style="width: 200px;" v-model="queryParams.itemName" placeholder="请输入产品名称" clearable
|
||||
@@ -63,6 +67,10 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dictType="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable multiple />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable multiple />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
||||
@@ -163,7 +171,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCoilWithIds } from "@/api/wms/coil";
|
||||
import {
|
||||
listPendingAction,
|
||||
} from '@/api/wms/pendingAction';
|
||||
@@ -216,7 +223,7 @@ export default {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
@@ -445,7 +452,7 @@ export default {
|
||||
fetchOutputList({
|
||||
...this.queryParams,
|
||||
...this.baseQueryParams,
|
||||
warehouseIds: this.warehouseIds.join(','),
|
||||
// warehouseIds: this.warehouseIds.join(','),
|
||||
}),
|
||||
]).then(([lossList, outputList]) => {
|
||||
// 将mergeCoils中存在的卷剔除
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dict-type="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getList">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
||||
@@ -147,7 +151,7 @@ export default {
|
||||
CoilTable,
|
||||
ColumnsSetting
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
|
||||
@@ -14,10 +14,14 @@
|
||||
<el-input style="width: 200px;" v-model="queryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<!-- <el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<el-select v-model="warehouseIds" collapse-tags multiple placeholder="请选择逻辑库位" style="width: 200px;">
|
||||
<el-option v-for="item in warehouseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="逻辑库位" prop="warehouseId">
|
||||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位"
|
||||
style="width: 100%; display: inline-block; width: 200px;" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称" prop="itemName">
|
||||
<el-input style="width: 200px;" v-model="queryParams.itemName" placeholder="请输入产品名称" clearable
|
||||
@@ -35,6 +39,10 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dict-type="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
||||
@@ -134,10 +142,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCoilWithIds } from "@/api/wms/coil";
|
||||
import {
|
||||
listPendingAction,
|
||||
} from '@/api/wms/pendingAction';
|
||||
import ProductInfo from "@/components/KLPService/Renderer/ProductInfo";
|
||||
import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
|
||||
import CoilNo from "@/components/KLPService/Renderer/CoilNo.vue";
|
||||
@@ -187,7 +191,7 @@ export default {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
@@ -410,7 +414,7 @@ export default {
|
||||
fetchOutputList({
|
||||
...this.queryParams,
|
||||
...this.baseQueryParams,
|
||||
warehouseIds: this.warehouseIds.join(','),
|
||||
// warehouseIds: this.warehouseIds.join(','),
|
||||
}),
|
||||
]).then(([lossList, outputList]) => {
|
||||
this.lossList = lossList
|
||||
|
||||
@@ -20,10 +20,14 @@
|
||||
<el-input style="width: 200px;" v-model="queryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位" prop="endTime">
|
||||
<!-- <el-form-item label="逻辑库位" prop="endTime">
|
||||
<el-select v-model="warehouseIds" collapse-tags multiple placeholder="请选择逻辑库位" style="width: 200px;">
|
||||
<el-option v-for="item in warehouseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="逻辑库位" prop="warehouseId">
|
||||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位"
|
||||
style="width: 100%; display: inline-block; width: 200px;" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称" prop="endTime">
|
||||
<el-input style="width: 200px;" v-model="queryParams.itemName" placeholder="请输入产品名称" clearable
|
||||
@@ -41,6 +45,10 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dict-type="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item prop="endTime">
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出</el-button>
|
||||
@@ -110,7 +118,7 @@ export default {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 工具函数:个位数补零,保证格式统一(比如 9 → 09,5 → 05)
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
@@ -200,7 +208,7 @@ export default {
|
||||
fetchOutputList({
|
||||
...this.queryParams,
|
||||
...this.baseQueryParams,
|
||||
warehouseIds: this.warehouseIds.join(','),
|
||||
// warehouseIds: this.warehouseIds.join(','),
|
||||
}).then((resList) => {
|
||||
this.list = resList
|
||||
this.loading = false
|
||||
|
||||
@@ -24,10 +24,14 @@
|
||||
<el-input style="width: 200px;" v-model="queryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位">
|
||||
<!-- <el-form-item label="逻辑库位">
|
||||
<el-select v-model="warehouseIds" collapse-tags multiple placeholder="请选择逻辑库位" style="width: 200px;">
|
||||
<el-option v-for="item in warehouseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="逻辑库位" prop="warehouseId">
|
||||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位"
|
||||
style="width: 100%; display: inline-block; width: 200px;" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称">
|
||||
<el-input style="width: 200px;" v-model="queryParams.itemName" placeholder="请输入产品名称" clearable
|
||||
@@ -45,6 +49,10 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dict-type="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
||||
@@ -187,7 +195,7 @@ export default {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
const addZero = (num) => num.toString().padStart(2, '0');
|
||||
const now = new Date();
|
||||
@@ -318,7 +326,7 @@ export default {
|
||||
fetchOutputList({
|
||||
...this.queryParams,
|
||||
...this.baseQueryParams,
|
||||
warehouseIds: this.warehouseIds.join(','),
|
||||
// warehouseIds: this.warehouseIds.join(','),
|
||||
}),
|
||||
]).then(([lossList, outputList]) => {
|
||||
this.lossList = lossList
|
||||
|
||||
@@ -14,10 +14,14 @@
|
||||
<el-input style="width: 200px;" v-model="queryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<!-- <el-form-item label="逻辑库位" prop="warehouseIds">
|
||||
<el-select v-model="warehouseIds" collapse-tags multiple placeholder="请选择逻辑库位" style="width: 200px;">
|
||||
<el-option v-for="item in warehouseOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="逻辑库位" prop="warehouseId">
|
||||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位"
|
||||
style="width: 100%; display: inline-block; width: 200px;" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称" prop="itemName">
|
||||
<el-input style="width: 200px;" v-model="queryParams.itemName" placeholder="请输入产品名称" clearable
|
||||
@@ -35,6 +39,10 @@
|
||||
<dict-select style="width: 200px;" v-model="queryParams.itemManufacturer" dict-type="coil_manufacturer"
|
||||
placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item label="品质" prop="qualityStatusCsv">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable @keyup.enter.native="handleQuery" multiple />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
||||
@@ -169,7 +177,7 @@ export default {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
|
||||
data() {
|
||||
// 获取当前日期(默认选中当天)
|
||||
const now = new Date()
|
||||
@@ -304,7 +312,7 @@ export default {
|
||||
fetchOutputList({
|
||||
...this.queryParams,
|
||||
...this.baseQueryParams,
|
||||
warehouseIds: this.warehouseIds.join(','),
|
||||
// warehouseIds: this.warehouseIds.join(','),
|
||||
}),
|
||||
]).then(([lossList, outputList]) => {
|
||||
this.lossList = lossList
|
||||
|
||||
@@ -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>> list(DrMillProcessRecipe query) {
|
||||
List<DrMillProcessRecipe> list = recipeService.selectList(query);
|
||||
// 每次查询时补齐缺失的 L3 工艺规程(幂等,已存在则跳过)
|
||||
syncService.syncRecipesToSpec(list);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R<DrMillProcessRecipe> detail(@PathVariable Long id) {
|
||||
return R.ok(recipeService.selectDetailById(id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R<Long> add(@RequestBody DrMillProcessRecipe recipe) {
|
||||
recipeService.save(recipe);
|
||||
// 新增方案后立即同步 L3 工艺规程
|
||||
syncService.syncRecipesToSpec(Collections.singletonList(recipe));
|
||||
return R.ok(recipe.getRecipeId());
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public R<Void> edit(@RequestBody DrMillProcessRecipe recipe) {
|
||||
recipeService.update(recipe);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@PathVariable Long[] ids) {
|
||||
recipeService.deleteByIds(ids);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
// ─── 版本 ────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/version/list/{recipeId}")
|
||||
public R<List<DrMillProcessRecipeVersion>> versionList(@PathVariable Long recipeId) {
|
||||
return R.ok(versionService.listByRecipeId(recipeId));
|
||||
}
|
||||
|
||||
@GetMapping("/version/{versionId}")
|
||||
public R<DrMillProcessRecipeVersion> versionDetail(@PathVariable Long versionId) {
|
||||
return R.ok(versionService.getDetailById(versionId));
|
||||
}
|
||||
|
||||
@PostMapping("/version")
|
||||
public R<Long> addVersion(@RequestBody DrMillProcessRecipeVersion version) {
|
||||
return R.ok(versionService.save(version));
|
||||
}
|
||||
|
||||
@PutMapping("/version")
|
||||
public R<Void> editVersion(@RequestBody DrMillProcessRecipeVersion version) {
|
||||
versionService.update(version);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PutMapping("/version/activate/{versionId}")
|
||||
public R<Void> activate(@PathVariable Long versionId) {
|
||||
versionService.activate(versionId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@DeleteMapping("/version/{versionId}")
|
||||
public R<Void> deleteVersion(@PathVariable Long versionId) {
|
||||
versionService.deleteById(versionId);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -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>> list(DrMillProductionPlan query) {
|
||||
return R.ok(planService.selectList(query));
|
||||
}
|
||||
|
||||
/** 实绩分页查询(按创建时间倒序,支持卷号/状态/时间范围过滤) */
|
||||
@GetMapping("/actual/page")
|
||||
public TableDataInfo<DrMillProductionPlan> actualPage(DrMillProductionPlan query) {
|
||||
return planService.selectPageList(query);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R<DrMillProductionPlan> detail(@PathVariable Long id) {
|
||||
return R.ok(planService.selectById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过待操作ID查询绑定计划(含道次),供录入页快捷写入
|
||||
* planNo = "DR" + actionId
|
||||
*/
|
||||
@GetMapping("/byAction/{actionId}")
|
||||
public R<DrMillProductionPlan> getByActionId(@PathVariable Long actionId) {
|
||||
return R.ok(planService.selectByActionId(actionId));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R<Void> add(@RequestBody DrMillProductionPlan plan) {
|
||||
planService.insert(plan);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public R<Void> edit(@RequestBody DrMillProductionPlan plan) {
|
||||
planService.update(plan);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public R<Void> remove(@PathVariable Long id) {
|
||||
planService.deleteById(id);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PutMapping("/moveUp/{id}")
|
||||
public R<Void> moveUp(@PathVariable Long id) {
|
||||
planService.moveUp(id);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PutMapping("/moveDown/{id}")
|
||||
public R<Void> moveDown(@PathVariable Long id) {
|
||||
planService.moveDown(id);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PutMapping("/finish/{id}")
|
||||
public R<Void> finish(@PathVariable Long id) {
|
||||
planService.finish(id);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -607,6 +607,16 @@ public class WmsMaterialCoilController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据入场钢卷号或当前钢卷号查询钢卷信息,供双机架计划绑定使用
|
||||
*
|
||||
* @param coilNo 入场钢卷号或当前钢卷号
|
||||
*/
|
||||
@GetMapping("/queryByCoilNo")
|
||||
public R<com.klp.domain.vo.WmsMaterialCoilVo> queryByCoilNo(@NotBlank(message = "钢卷号不能为空") @RequestParam String coilNo) {
|
||||
return R.ok(iWmsMaterialCoilService.queryByCoilNo(coilNo));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 冷硬卷切边统计
|
||||
|
||||
33
klp-wms/src/main/java/com/klp/domain/DrMillProcessPass.java
Normal file
33
klp-wms/src/main/java/com/klp/domain/DrMillProcessPass.java
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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<DrMillProcessPass> passList;
|
||||
}
|
||||
@@ -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<DrMillProcessPass> passList;
|
||||
}
|
||||
@@ -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<DrMillProcessPass> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<DrMillProcessPass> selectByVersionId(Long versionId);
|
||||
List<DrMillProcessPass> selectByRecipeId(Long recipeId);
|
||||
int insertBatch(List<DrMillProcessPass> list);
|
||||
int deleteByVersionId(Long versionId);
|
||||
int deleteByRecipeId(Long recipeId);
|
||||
/** 查出所有 version_id 为空的道次所属 recipe_id(去重) */
|
||||
List<Long> selectDistinctRecipeIdsWithOrphanPasses();
|
||||
/** 将指定方案下所有 version_id 为空的道次批量设置 version_id */
|
||||
int updateVersionIdForOrphans(@Param("recipeId") Long recipeId,
|
||||
@Param("versionId") Long versionId);
|
||||
}
|
||||
@@ -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<DrMillProcessRecipe> selectList(DrMillProcessRecipe query);
|
||||
DrMillProcessRecipe selectById(Long recipeId);
|
||||
int insert(DrMillProcessRecipe recipe);
|
||||
int update(DrMillProcessRecipe recipe);
|
||||
int deleteBatchByIds(Long[] ids);
|
||||
}
|
||||
@@ -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<DrMillProcessRecipeVersion> 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);
|
||||
}
|
||||
@@ -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<DrMillProductionPlan> selectList(DrMillProductionPlan query);
|
||||
/** 分页查询(配合 PageHelper 或手动 LIMIT/OFFSET) */
|
||||
List<DrMillProductionPlan> 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);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.klp.service;
|
||||
|
||||
import com.klp.domain.DrMillProcessRecipe;
|
||||
import java.util.List;
|
||||
|
||||
public interface IDrMillProcessRecipeService {
|
||||
List<DrMillProcessRecipe> selectList(DrMillProcessRecipe query);
|
||||
DrMillProcessRecipe selectDetailById(Long id);
|
||||
int save(DrMillProcessRecipe recipe);
|
||||
int update(DrMillProcessRecipe recipe);
|
||||
int deleteByIds(Long[] ids);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.klp.service;
|
||||
|
||||
import com.klp.domain.DrMillProcessRecipeVersion;
|
||||
import java.util.List;
|
||||
|
||||
public interface IDrMillProcessRecipeVersionService {
|
||||
List<DrMillProcessRecipeVersion> listByRecipeId(Long recipeId);
|
||||
DrMillProcessRecipeVersion getDetailById(Long versionId);
|
||||
Long save(DrMillProcessRecipeVersion version);
|
||||
void update(DrMillProcessRecipeVersion version);
|
||||
void activate(Long versionId);
|
||||
void deleteById(Long versionId);
|
||||
}
|
||||
@@ -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<DrMillProductionPlan> selectList(DrMillProductionPlan query);
|
||||
/** 分页查询实绩(按创建时间倒序) */
|
||||
TableDataInfo<DrMillProductionPlan> 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);
|
||||
}
|
||||
@@ -344,5 +344,10 @@ public interface IWmsMaterialCoilService {
|
||||
* @param response HTTP响应对象
|
||||
*/
|
||||
void exportAbnormalReport(WmsMaterialCoilBo bo, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 根据入场钢卷号或当前钢卷号查询钢卷,供双机架计划绑定使用
|
||||
*/
|
||||
com.klp.domain.vo.WmsMaterialCoilVo queryByCoilNo(String coilNo);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Long> 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);
|
||||
}
|
||||
}
|
||||
@@ -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<DrMillProcessRecipe> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<DrMillProcessRecipeVersion> 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<DrMillProcessPass> 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);
|
||||
}
|
||||
}
|
||||
@@ -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<DrMillProductionPlan> selectList(DrMillProductionPlan query) {
|
||||
return planMapper.selectList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<DrMillProductionPlan> 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<DrMillProductionPlan> rows = planMapper.selectPageList(query);
|
||||
TableDataInfo<DrMillProductionPlan> 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<DrMillProductionPlan> 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<DrMillProductionPlan> 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<DrMillProductionPlan> 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);
|
||||
}
|
||||
}
|
||||
@@ -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)同步服务
|
||||
* <p>
|
||||
* 注意:此 Service 不标注 @DS,默认走 master 数据源,
|
||||
* 供 Controller 在 double-rack 查询完方案列表后调用,
|
||||
* 将缺失的 wms_process_spec 记录自动补齐。
|
||||
* </p>
|
||||
*/
|
||||
@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<DrMillProcessRecipe> 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<WmsProcessSpec> 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<WmsProductionLine> 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();
|
||||
}
|
||||
}
|
||||
@@ -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<DrMillProductionPlan> 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改钢卷待操作
|
||||
*/
|
||||
|
||||
@@ -5521,5 +5521,15 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
|
||||
return baseMapper.update(null, updateWrapper) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WmsMaterialCoilVo queryByCoilNo(String coilNo) {
|
||||
LambdaQueryWrapper<WmsMaterialCoil> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(WmsMaterialCoil::getEnterCoilNo, coilNo)
|
||||
.or()
|
||||
.eq(WmsMaterialCoil::getCurrentCoilNo, coilNo);
|
||||
lqw.last("LIMIT 1");
|
||||
return baseMapper.selectVoOne(lqw);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
33
klp-wms/src/main/java/com/klp/task/DrMigrationRunner.java
Normal file
33
klp-wms/src/main/java/com/klp/task/DrMigrationRunner.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.mapper.DrMillProcessPassMapper">
|
||||
|
||||
<resultMap id="BaseRM" type="com.klp.domain.DrMillProcessPass">
|
||||
<id property="passId" column="pass_id"/>
|
||||
<result property="recipeId" column="recipe_id"/>
|
||||
<result property="versionId" column="version_id"/>
|
||||
<result property="passNo" column="pass_no"/>
|
||||
<result property="inThick" column="in_thick"/>
|
||||
<result property="outThick" column="out_thick"/>
|
||||
<result property="width" column="width"/>
|
||||
<result property="rollForce" column="roll_force"/>
|
||||
<result property="inTension" column="in_tension"/>
|
||||
<result property="outTension" column="out_tension"/>
|
||||
<result property="maxSpeed" column="max_speed"/>
|
||||
<result property="inUnitTension" column="in_unit_tension"/>
|
||||
<result property="outUnitTension" column="out_unit_tension"/>
|
||||
<result property="reduction" column="reduction"/>
|
||||
<result property="totalReduction" column="total_reduction"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectByVersionId" resultMap="BaseRM">
|
||||
SELECT pass_id, 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,
|
||||
del_flag, create_by, create_time, update_by, update_time, remark
|
||||
FROM mill_process_pass
|
||||
WHERE version_id = #{versionId} AND del_flag = '0'
|
||||
ORDER BY pass_no ASC
|
||||
</select>
|
||||
|
||||
<select id="selectByRecipeId" resultMap="BaseRM">
|
||||
SELECT pass_id, 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,
|
||||
del_flag, create_by, create_time, update_by, update_time, remark
|
||||
FROM mill_process_pass
|
||||
WHERE recipe_id = #{recipeId} AND del_flag = '0'
|
||||
ORDER BY pass_no ASC
|
||||
</select>
|
||||
|
||||
<insert id="insertBatch">
|
||||
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
|
||||
<foreach collection="list" item="p" separator=",">
|
||||
(#{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')
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<update id="deleteByVersionId">
|
||||
UPDATE mill_process_pass SET del_flag = '2', update_time = NOW()
|
||||
WHERE version_id = #{versionId}
|
||||
</update>
|
||||
|
||||
<update id="deleteByRecipeId">
|
||||
UPDATE mill_process_pass SET del_flag = '2', update_time = NOW()
|
||||
WHERE recipe_id = #{recipeId}
|
||||
</update>
|
||||
|
||||
<select id="selectDistinctRecipeIdsWithOrphanPasses" resultType="java.lang.Long">
|
||||
SELECT DISTINCT recipe_id
|
||||
FROM mill_process_pass
|
||||
WHERE version_id IS NULL AND del_flag = '0'
|
||||
</select>
|
||||
|
||||
<update id="updateVersionIdForOrphans">
|
||||
UPDATE mill_process_pass
|
||||
SET version_id = #{versionId},
|
||||
update_time = NOW()
|
||||
WHERE recipe_id = #{recipeId}
|
||||
AND version_id IS NULL
|
||||
AND del_flag = '0'
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.mapper.DrMillProcessRecipeMapper">
|
||||
|
||||
<resultMap id="BaseRM" type="com.klp.domain.DrMillProcessRecipe">
|
||||
<id property="recipeId" column="recipe_id"/>
|
||||
<result property="recipeNo" column="recipe_no"/>
|
||||
<result property="alloyNo" column="alloy_no"/>
|
||||
<result property="passCount" column="pass_count"/>
|
||||
<result property="inThick" column="in_thick"/>
|
||||
<result property="outThick" column="out_thick"/>
|
||||
<result property="outWidth" column="out_width"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="cols">
|
||||
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
|
||||
</sql>
|
||||
|
||||
<select id="selectList" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/>
|
||||
FROM mill_process_recipe
|
||||
WHERE del_flag = '0'
|
||||
<if test="recipeNo != null and recipeNo != ''">
|
||||
AND recipe_no LIKE CONCAT('%', #{recipeNo}, '%')
|
||||
</if>
|
||||
<if test="alloyNo != null and alloyNo != ''">
|
||||
AND alloy_no LIKE CONCAT('%', #{alloyNo}, '%')
|
||||
</if>
|
||||
<if test="status != null and status != ''">
|
||||
AND status = #{status}
|
||||
</if>
|
||||
ORDER BY recipe_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectById" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/> FROM mill_process_recipe
|
||||
WHERE recipe_id = #{recipeId} AND del_flag = '0'
|
||||
</select>
|
||||
|
||||
<insert id="insert" useGeneratedKeys="true" keyProperty="recipeId">
|
||||
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'
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="update">
|
||||
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>
|
||||
|
||||
<update id="deleteBatchByIds">
|
||||
UPDATE mill_process_recipe SET del_flag = '2', update_time = NOW()
|
||||
WHERE recipe_id IN
|
||||
<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach>
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.mapper.DrMillProcessRecipeVersionMapper">
|
||||
|
||||
<resultMap id="BaseRM" type="com.klp.domain.DrMillProcessRecipeVersion">
|
||||
<id property="versionId" column="version_id"/>
|
||||
<result property="recipeId" column="recipe_id"/>
|
||||
<result property="versionCode" column="version_code"/>
|
||||
<result property="isActive" column="is_active"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="cols">
|
||||
version_id, recipe_id, version_code, is_active, status,
|
||||
create_by, create_time, update_by, update_time, remark, del_flag
|
||||
</sql>
|
||||
|
||||
<select id="selectByRecipeId" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/>
|
||||
FROM mill_process_recipe_version
|
||||
WHERE recipe_id = #{recipeId} AND del_flag = '0'
|
||||
ORDER BY version_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectV1ByRecipeId" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/>
|
||||
FROM mill_process_recipe_version
|
||||
WHERE recipe_id = #{recipeId} AND version_code = 'V1.0' AND del_flag = '0'
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectActiveByRecipeId" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/>
|
||||
FROM mill_process_recipe_version
|
||||
WHERE recipe_id = #{recipeId} AND is_active = 1 AND del_flag = '0'
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectById" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/>
|
||||
FROM mill_process_recipe_version
|
||||
WHERE version_id = #{versionId} AND del_flag = '0'
|
||||
</select>
|
||||
|
||||
<insert id="insert" useGeneratedKeys="true" keyProperty="versionId">
|
||||
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'
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="update">
|
||||
UPDATE mill_process_recipe_version
|
||||
SET version_code = #{versionCode},
|
||||
status = #{status},
|
||||
update_by = #{updateBy},
|
||||
update_time = NOW(),
|
||||
remark = #{remark}
|
||||
WHERE version_id = #{versionId}
|
||||
</update>
|
||||
|
||||
<update id="deleteById">
|
||||
UPDATE mill_process_recipe_version SET del_flag = '2', update_time = NOW()
|
||||
WHERE version_id = #{versionId}
|
||||
</update>
|
||||
|
||||
<update id="deleteByRecipeIds">
|
||||
UPDATE mill_process_recipe_version SET del_flag = '2', update_time = NOW()
|
||||
WHERE recipe_id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach>
|
||||
</update>
|
||||
|
||||
<update id="deactivateOthers">
|
||||
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>
|
||||
|
||||
<update id="activate">
|
||||
UPDATE mill_process_recipe_version
|
||||
SET is_active = 1, status = '1', update_time = NOW()
|
||||
WHERE version_id = #{versionId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
160
klp-wms/src/main/resources/mapper/DrMillProductionPlanMapper.xml
Normal file
160
klp-wms/src/main/resources/mapper/DrMillProductionPlanMapper.xml
Normal file
@@ -0,0 +1,160 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.mapper.DrMillProductionPlanMapper">
|
||||
|
||||
<resultMap id="BaseRM" type="com.klp.domain.DrMillProductionPlan">
|
||||
<id property="planId" column="plan_id"/>
|
||||
<result property="planNo" column="plan_no"/>
|
||||
<result property="planStatus" column="plan_status"/>
|
||||
<result property="prodStatus" column="prod_status"/>
|
||||
<result property="sortNo" column="sort_no"/>
|
||||
<result property="inMatNo" column="in_mat_no"/>
|
||||
<result property="alloyNo" column="sg_sign"/>
|
||||
<result property="inMatThick" column="in_mat_thick"/>
|
||||
<result property="inMatWidth" column="in_mat_width"/>
|
||||
<result property="inMatWeight" column="in_mat_wt"/>
|
||||
<result property="inMatLength" column="in_mat_len"/>
|
||||
<result property="inMatId" column="in_mat_in_dia"/>
|
||||
<result property="inMatOd" column="in_mat_dia"/>
|
||||
<result property="outThick" column="out_thick"/>
|
||||
<result property="passCount" column="pass_count"/>
|
||||
<result property="recipeId" column="recipe_id"/>
|
||||
<result property="recipeNo" column="recipe_no"/>
|
||||
<result property="versionId" column="version_id"/>
|
||||
<result property="enterCoilNo" column="enter_coil_no"/>
|
||||
<result property="currentCoilNo" column="current_coil_no"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="cols">
|
||||
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
|
||||
</sql>
|
||||
|
||||
<select id="selectList" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/>
|
||||
FROM mill_production_plan
|
||||
WHERE del_flag = '0'
|
||||
<if test="inMatNo != null and inMatNo != ''">
|
||||
AND (in_mat_no LIKE CONCAT('%', #{inMatNo}, '%')
|
||||
OR enter_coil_no LIKE CONCAT('%', #{inMatNo}, '%')
|
||||
OR current_coil_no LIKE CONCAT('%', #{inMatNo}, '%'))
|
||||
</if>
|
||||
<if test="planStatus != null and planStatus != ''">
|
||||
AND plan_status = #{planStatus}
|
||||
</if>
|
||||
<if test="prodStatus != null and prodStatus != ''">
|
||||
AND prod_status = #{prodStatus}
|
||||
</if>
|
||||
ORDER BY sort_no ASC, plan_id ASC
|
||||
</select>
|
||||
|
||||
<!-- 实绩分页:按创建时间倒序,支持卷号/状态/时间范围过滤 -->
|
||||
<sql id="actualWhere">
|
||||
WHERE del_flag = '0'
|
||||
<if test="inMatNo != null and inMatNo != ''">
|
||||
AND (in_mat_no LIKE CONCAT('%',#{inMatNo},'%')
|
||||
OR enter_coil_no LIKE CONCAT('%',#{inMatNo},'%')
|
||||
OR current_coil_no LIKE CONCAT('%',#{inMatNo},'%'))
|
||||
</if>
|
||||
<if test="planStatus != null and planStatus != ''">
|
||||
AND plan_status = #{planStatus}
|
||||
</if>
|
||||
<if test="createStartTime != null and createStartTime != ''">
|
||||
AND create_time >= #{createStartTime}
|
||||
</if>
|
||||
<if test="createEndTime != null and createEndTime != ''">
|
||||
AND create_time <= #{createEndTime}
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="selectPageList" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/>
|
||||
FROM mill_production_plan
|
||||
<include refid="actualWhere"/>
|
||||
ORDER BY create_time DESC
|
||||
<if test="pageSize != null and pageNum != null">
|
||||
LIMIT #{pageSize} OFFSET #{offset}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="countPageList" resultType="long">
|
||||
SELECT COUNT(*) FROM mill_production_plan
|
||||
<include refid="actualWhere"/>
|
||||
</select>
|
||||
|
||||
<select id="selectById" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/> FROM mill_production_plan
|
||||
WHERE plan_id = #{planId} AND del_flag = '0'
|
||||
</select>
|
||||
|
||||
<select id="selectByPlanNo" resultMap="BaseRM">
|
||||
SELECT <include refid="cols"/> FROM mill_production_plan
|
||||
WHERE plan_no = #{planNo} AND del_flag = '0'
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="countByStatus" resultType="int">
|
||||
SELECT COUNT(*) FROM mill_production_plan WHERE del_flag = '0' AND plan_status = #{status}
|
||||
</select>
|
||||
|
||||
<insert id="insert" useGeneratedKeys="true" keyProperty="planId">
|
||||
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'
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="update">
|
||||
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>
|
||||
|
||||
<update id="deleteById">
|
||||
UPDATE mill_production_plan SET del_flag = '2', update_time = NOW()
|
||||
WHERE plan_id = #{planId}
|
||||
</update>
|
||||
|
||||
<update id="updateSortNo">
|
||||
UPDATE mill_production_plan SET sort_no = #{sortNo} WHERE plan_id = #{planId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user