Files
klp-oa/klp-ui/src/views/wms/coil/do/search.vue
砂糖 03d8ba1d2f feat(钢卷管理): 新增调制度和镀层种类字段
在钢卷管理的多个页面和组件中添加调制度(temperGrade)和镀层种类(coatingType)字段,包括表单输入、显示和查询功能。同时优化了部分页面布局和代码结构,移除了不再使用的质量状态枚举定义
2026-01-22 10:20:58 +08:00

871 lines
27 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container acid-do-container">
<el-row :gutter="20">
<el-col :span="12">
<div class="section-card">
<!-- 入库 -->
<div class="section-header">
<h3 class="section-title">查询钢卷</h3>
</div>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="form.enterCoilNo" placeholder="请输入入场钢卷号" :disabled="form.coilId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model="form.currentCoilNo" placeholder="请输入当前钢卷号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="!form.coilId" label="厂家原料卷号" prop="supplierCoilNo">
<el-input v-model="form.supplierCoilNo" placeholder="请输入厂家原料卷号" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="所在库位" prop="warehouseId">
<warehouse-select v-model="form.warehouseId" placeholder="请选择仓库/库区/库位" style="width: 100%;"
clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实际库区" prop="actualWarehouseId">
<actual-warehouse-select v-model="form.actualWarehouseId" placeholder="请选择实际库区"
style="width: 100%;" clearable
:canSelectDisabled="true" :canSelectLevel2="true" :clearInput="false" :showEmpty="true" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="班组" prop="team">
<el-select v-model="form.team" placeholder="请选择班组" style="width: 100%" :disabled="readonly">
<el-option key="甲" label="甲" value="甲" />
<el-option key="乙" label="乙" value="乙" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="长度" prop="length">
<el-input v-model="form.length" placeholder="请输入长度" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="材料类型" prop="materialType" v-if="!form.coilId">
<el-select v-model="form.materialType" placeholder="请选择材料类型" @change="handleMaterialTypeChange">
<el-option label="成品" value="成品" />
<el-option label="原料" value="原料" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="getItemLabel" prop="itemId" v-if="!form.coilId">
<product-select v-if="form.itemType == 'product'" v-model="form.itemId" clearable />
<raw-material-select v-else-if="form.itemType == 'raw_material'" v-model="form.itemId" clearable />
<div v-else>请先选择材料类型</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="质量状态" prop="qualityStatus">
<el-select v-model="form.qualityStatus" placeholder="请选择质量状态" style="width: 100%"
:disabled="readonly">
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="切边要求" prop="trimmingRequirement">
<el-select v-model="form.trimmingRequirement" placeholder="请选择切边要求" style="width: 100%"
:disabled="readonly">
<el-option label="净边料" value="净边料" />
<el-option label="毛边料" value="毛边料" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="打包状态" prop="packingStatus">
<el-input v-model="form.packingStatus" placeholder="请输入打包状态">
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="包装要求" prop="packagingRequirement">
<el-select v-model="form.packagingRequirement" placeholder="请选择包装要求" style="width: 100%"
:disabled="readonly">
<el-option label="裸包" value="裸包" />
<el-option label="普包" value="普包" />
<el-option label="简包" value="简包" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="毛重" prop="grossWeight">
<el-input v-model="form.grossWeight" placeholder="请输入毛重" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="净重" prop="netWeight">
<el-input v-model="form.netWeight" placeholder="请输入净重" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="长度" prop="length">
<el-input v-model="form.length" placeholder="请输入长度" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="form.temperGrade" placeholder="请输入调制度" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="镀层种类" prop="coatingType">
<el-input v-model="form.coatingType" placeholder="请输入镀层种类" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</el-form-item>
</el-form>
</div>
</el-col>
<!-- 右侧物料列表 -->
<el-col :span="12">
<div class="section-card material-section">
<div class="section-header">
<h3 class="section-title">钢卷列表</h3>
<el-button size="mini" icon="el-icon-refresh" @click="getMaterialCoil">刷新</el-button>
</div>
<!-- 物料卡片列表 -->
<div v-loading="materialLoading" class="card-grid-container">
<div v-if="materialCoilList.length === 0" class="empty-state">
<i class="el-icon-box"></i>
<p>未找到钢卷</p>
</div>
<div v-for="(item, index) in materialCoilList" :key="item.coilId || index" class="material-card">
<div class="card-header">
<div class="header-left">
<el-tag type="info" size="small" class="coil-no-tag">{{ item.currentCoilNo }}</el-tag>
<span class="material-type">{{ item.materialType || '原料' }}</span>
<el-popover v-if="item.rawMaterial || item.product" placement="top" width="280" trigger="hover"
popper-class="material-params-popover">
<div class="material-params-content">
<div class="params-title">
{{ item.itemType === 'raw_material' ? (item.rawMaterial && item.rawMaterial.rawMaterialName ||
'—') : (item.product && item.product.productName || '—') }}
</div>
<div class="params-list">
<div class="param-item" v-if="item.itemType === 'raw_material' && item.rawMaterial">
<div class="param-row" v-if="item.rawMaterial.specification">
<span class="param-label">规格</span>
<span class="param-value">{{ item.rawMaterial.specification }}</span>
</div>
</div>
<div class="param-item" v-else-if="item.itemType === 'product' && item.product">
<div class="param-row" v-if="item.product.specification">
<span class="param-label">规格</span>
<span class="param-value">{{ item.product.specification }}</span>
</div>
</div>
<div class="param-divider"></div>
<div class="param-item">
<div class="param-row" v-if="item.grossWeight">
<span class="param-label">毛重</span>
<span class="param-value">{{ item.grossWeight }}t</span>
</div>
<div class="param-row" v-if="item.netWeight">
<span class="param-label">净重</span>
<span class="param-value">{{ item.netWeight }}t</span>
</div>
<div class="param-row" v-if="item.length">
<span class="param-label">长度</span>
<span class="param-value">{{ item.length }}mm</span>
</div>
<div class="param-row" v-if="item.temperGrade">
<span class="param-label">调制度</span>
<span class="param-value">{{ item.temperGrade }}</span>
</div>
<div class="param-row" v-if="item.coatingType">
<span class="param-label">镀层种类</span>
<span class="param-value">{{ item.coatingType }}</span>
</div>
<div class="param-row" v-if="item.team">
<span class="param-label">班组</span>
<span class="param-value">{{ item.team }}</span>
</div>
<div class="param-row" v-if="item.updateTime">
<span class="param-label">更新时间</span>
<span class="param-value">{{ parseTime(item.updateTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</div>
<div class="param-row" v-if="item.updateBy">
<span class="param-label">更新人</span>
<span class="param-value">{{ item.updateBy }}</span>
</div>
<div class="param-row" v-if="item.remark">
<span class="param-label">备注</span>
<span class="param-value">{{ item.remark }}</span>
</div>
</div>
</div>
</div>
<i slot="reference" class="el-icon-setting param-icon"></i>
</el-popover>
</div>
</div>
<div class="card-body">
<div class="info-list">
<div class="info-item">
<span class="info-label">入场</span>
<span class="info-value" :title="item.enterCoilNo">{{ item.enterCoilNo || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">厂家</span>
<span class="info-value" :title="item.supplierCoilNo">{{ item.supplierCoilNo || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">库位</span>
<span class="info-value" :title="item.warehouseName">{{ item.warehouseName || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">库区</span>
<span class="info-value" :title="item.actualWarehouseName">{{ item.actualWarehouseName || '—'
}}</span>
</div>
<div class="info-item">
<span class="info-label">重量</span>
<span class="info-value">{{ item.netWeight || '—' }}t</span>
</div>
</div>
</div>
<!-- <div class="card-footer">
<el-button v-if="item.dataType == 1" type="primary" icon="el-icon-check" size="mini"
@click="handlePickMaterial(item)" :loading="item.picking" class="action-btn">领料</el-button>
</div> -->
</div>
</div>
<!-- 分页 -->
<pagination v-show="materialTotal > 0" :total="materialTotal" :page.sync="form.pageNum"
:limit.sync="form.pageSize" @pagination="getMaterialCoil" />
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import { listMaterialCoil } from '@/api/wms/coil'
import { listPendingAction } from '@/api/wms/pendingAction'
import { parseTime } from '@/utils/klp'
import ProductInfo from '@/components/KLPService/Renderer/ProductInfo'
import RawMaterialInfo from '@/components/KLPService/Renderer/RawMaterialInfo'
import WarehouseSelect from '@/components/KLPService/WarehouseSelect'
import ActualWarehouseSelect from '@/components/KLPService/ActualWarehouseSelect'
import ProductSelect from '@/components/KLPService/ProductSelect'
import RawMaterialSelect from '@/components/KLPService/RawMaterialSelect'
export default {
name: 'AcidDo',
dicts: ['action_type'],
components: {
ProductInfo,
RawMaterialInfo,
ActualWarehouseSelect,
WarehouseSelect,
ProductSelect,
RawMaterialSelect,
},
dicts: ['coil_quality_status'],
data() {
return {
// 物料列表相关
materialLoading: false,
materialCoilList: [],
materialTotal: 0,
materialQueryParams: {
pageNum: 1,
pageSize: 20,
dataType: 1,
materialType: '原料',
enterCoilNo: null,
currentCoilNo: null
},
// 表单参数
form: {
dataType: 1,
// materialType: '原料',
materialType: null,
enterCoilNo: null,
currentCoilNo: null,
itemId: null,
itemType: null,
netWeight: null,
grossWeight: null,
remark: null,
trimmingRequirement: null,
packingStatus: null,
packagingRequirement: null,
pageNum: 1,
pageSize: 10,
},
// 待操作列表相关
actionLoading: false,
pendingActionList: [],
actionTotal: 0,
actionQueryParams: {
pageNum: 1,
pageSize: 20,
currentCoilNo: null,
actionType: null, // 将在created中设置为酸连轧工序的actionType
actionStatus: null
}
}
},
computed: {
// 获取酸连轧工序的actionType值
acidRollingActionType() {
if (!this.dict.type.action_type) return null
const acidAction = this.dict.type.action_type.find(item => {
const label = item.label || ''
return label.includes('酸连轧') || label.includes('酸连')
})
return acidAction ? parseInt(acidAction.value) : null
},
// 动态显示标签
getItemLabel() {
if (this.form.materialType === '成品') {
return '产品类型';
} else if (this.form.materialType === '原料') {
return '原料类型';
}
return '物品类型';
},
},
watch: {
// 监听字典数据加载当acidRollingActionType有值时自动加载待操作列表
acidRollingActionType(newVal) {
if (newVal && !this.actionQueryParams.actionType) {
this.actionQueryParams.actionType = newVal
// 如果待操作列表为空,则加载数据
if (this.pendingActionList.length === 0) {
this.getPendingAction()
}
}
}
},
methods: {
parseTime,
submitForm() {
this.getMaterialCoil()
},
// 取消操作
cancel() {
this.form = {};
this.$refs.form.resetFields();
this.buttonLoading = false;
},
// 处理材料类型变化
handleMaterialTypeChange(value) {
// 清空物品选择
this.form.itemId = null;
// 根据材料类型设置物品类型
if (value === '成品') {
this.form.itemType = 'product';
} else if (value === '原料') {
this.form.itemType = 'raw_material';
}
},
// ========== 物料列表相关方法 ==========
/** 查询物料列表 */
getMaterialCoil() {
this.materialLoading = true
listMaterialCoil(this.form).then(response => {
this.materialCoilList = response.rows || []
this.materialTotal = response.total || 0
this.materialLoading = false
}).catch(() => {
this.materialLoading = false
})
},
/** 物料搜索 */
handleMaterialQuery() {
this.form.pageNum = 1
this.getMaterialCoil()
},
/** 重置物料搜索 */
resetMaterialQuery() {
this.resetForm('materialQueryForm')
this.form.enterCoilNo = null
this.form.currentCoilNo = null
this.handleMaterialQuery()
},
/** 领料操作 */
// handlePickMaterial(row) {
// if (!this.acidRollingActionType) {
// this.$message.error('未找到酸连轧工序操作类型,请检查字典配置')
// return
// }
// this.$set(row, 'picking', true)
// const pendingData = {
// coilId: row.coilId,
// currentCoilNo: row.currentCoilNo,
// actionType: this.acidRollingActionType,
// actionStatus: 0, // 待处理
// sourceType: 'manual', // 手动创建
// warehouseId: row.warehouseId,
// priority: 0, // 默认普通优先级
// remark: `PC端领料创建-酸连轧工序`
// }
// addPendingAction(pendingData).then(response => {
// if (response.code === 200) {
// this.$message.success('领料成功,已创建待操作任务')
// this.getPendingAction() // 刷新待操作列表
// } else {
// this.$message.error(response.msg || '领料失败')
// }
// }).catch(error => {
// console.error('领料失败:', error)
// this.$message.error('领料失败,请重试')
// }).finally(() => {
// this.$set(row, 'picking', false)
// })
// },
// ========== 待操作列表相关方法 ==========
/** 查询待操作列表 */
getPendingAction() {
// 确保只查询酸连轧工序的待操作
if (!this.acidRollingActionType) {
console.warn('未找到酸连轧工序操作类型,请检查字典配置')
this.pendingActionList = []
this.actionTotal = 0
this.actionLoading = false
return
}
this.actionLoading = true
// 强制使用酸连轧工序的 actionType忽略查询参数中的 actionType
const queryParams = {
...this.actionQueryParams,
actionType: this.acidRollingActionType
}
listPendingAction(queryParams).then(response => {
this.pendingActionList = response.rows || []
this.actionTotal = response.total || 0
this.actionLoading = false
}).catch(() => {
this.actionLoading = false
})
},
}
}
</script>
<style scoped lang="scss">
.acid-do-container {
background-color: #f5f7fa;
padding: 20px;
min-height: calc(100vh - 84px);
}
.section-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 4px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 2px solid #e4e7ed;
}
.section-title {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #303133;
}
.material-section {
.section-header {
border-bottom-color: #409eff;
}
.section-title {
color: #409eff;
}
}
.action-section {
.section-header {
border-bottom-color: #67c23a;
}
.section-title {
color: #67c23a;
}
}
.query-form {
margin-bottom: 16px;
padding: 12px;
background-color: #fafafa;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
// 卡片网格容器
.card-grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
max-height: calc(100vh - 320px);
overflow-y: auto;
padding-right: 4px;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
&:hover {
background: #a8a8a8;
}
}
@media (min-width: 1600px) {
grid-template-columns: repeat(4, 1fr);
}
}
// 空状态
.empty-state {
text-align: center;
padding: 60px 20px;
color: #909399;
i {
font-size: 48px;
margin-bottom: 16px;
display: block;
color: #c0c4cc;
}
p {
margin: 0;
font-size: 14px;
}
}
// 物料卡片
.material-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 3px;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
height: 100%;
&:hover {
border-color: #409eff;
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.12);
}
.card-header {
padding: 6px 8px;
border-bottom: 1px solid #e4e7ed;
background-color: #fafafa;
.header-left {
display: flex;
align-items: center;
gap: 6px;
}
.coil-no-tag {
font-weight: 600;
font-size: 11px;
padding: 2px 6px;
}
.material-type {
font-size: 11px;
color: #606266;
font-weight: 500;
}
.param-icon {
font-size: 13px;
color: #909399;
cursor: pointer;
transition: color 0.3s;
&:hover {
color: #409eff;
}
}
}
.card-body {
padding: 8px;
flex: 1;
.info-list {
.info-item {
display: flex;
align-items: center;
margin-bottom: 4px;
font-size: 11px;
line-height: 1.4;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #909399;
white-space: nowrap;
margin-right: 4px;
min-width: 40px;
font-size: 11px;
}
.info-value {
color: #303133;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 11px;
}
}
}
}
.card-footer {
padding: 6px 8px;
border-top: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: center;
.action-btn {
width: 100%;
padding: 5px 10px;
font-size: 11px;
}
}
}
// 待操作卡片
.action-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 4px;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
height: 100%;
&:hover {
border-color: #67c23a;
box-shadow: 0 2px 8px rgba(103, 194, 58, 0.15);
}
&.urgent-card {
border-left: 4px solid #f56c6c;
background-color: #fef0f0;
&:hover {
border-color: #f56c6c;
box-shadow: 0 2px 8px rgba(245, 108, 108, 0.2);
}
}
&.important-card {
border-left: 4px solid #e6a23c;
background-color: #fdf6ec;
&:hover {
border-color: #e6a23c;
box-shadow: 0 2px 8px rgba(230, 162, 60, 0.2);
}
}
.card-header {
padding: 10px 12px;
border-bottom: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: space-between;
align-items: center;
.coil-no-tag {
font-weight: 600;
font-size: 12px;
}
.status-tags {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
}
.card-body {
padding: 12px;
flex: 1;
.info-list {
.info-item {
display: flex;
align-items: center;
margin-bottom: 8px;
font-size: 12px;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #909399;
white-space: nowrap;
margin-right: 6px;
min-width: 50px;
}
.info-value {
color: #303133;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.action-type-tag {
font-size: 11px;
}
}
}
}
.card-footer {
padding: 10px 12px;
border-top: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: center;
gap: 6px;
.action-btn {
flex: 1;
font-size: 12px;
padding: 6px 8px;
}
}
}
// 分页样式
::v-deep .pagination-container {
margin-top: 16px;
padding: 12px;
background-color: #fafafa;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
// 参数弹出框样式
::v-deep .material-params-popover {
.material-params-content {
.params-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #e4e7ed;
}
.params-list {
.param-item {
.param-row {
display: flex;
margin-bottom: 6px;
font-size: 12px;
line-height: 1.5;
&:last-child {
margin-bottom: 0;
}
.param-label {
color: #909399;
min-width: 70px;
margin-right: 8px;
}
.param-value {
color: #303133;
flex: 1;
word-break: break-all;
}
}
}
.param-divider {
height: 1px;
background-color: #e4e7ed;
margin: 10px 0;
}
}
}
}
</style>