Files
klp-oa/klp-ui/src/views/wms/coil/do/packing.vue
砂糖 aacf433462 feat: 修改打包状态为原料材质并优化异常管理功能
修改所有打包状态字段为原料材质,统一业务术语
重构异常管理功能,新增异常记录列表和删除功能
优化分条钢卷面板显示更多物料信息
将切边要求和包装要求改为下拉选择框
2026-03-30 13:13:46 +08:00

775 lines
22 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">
<el-row :gutter="20">
<el-col :span="12" v-loading="formLoading">
<div class="section-card">
<div class="section-header">
<h3 class="section-title">钢卷打包</h3>
</div>
<!-- 选择产品 -->
<el-form label-width="100px">
<el-form-item label="钢卷" prop="coilId">
<coil-selector v-model="form.coilId" :use-trigger="true" @select="handleItemChange"
:filters="coilFilters" />
</el-form-item>
</el-form>
<el-form ref="form" :model="form" :rules="rules" label-width="100px" disabled>
<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 />
</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-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" placeholder="请选择成品"
style="width: 100%;" clearable />
<raw-material-select v-else-if="form.itemType == 'raw_material'" v-model="form.itemId"
placeholder="请选择原料" style="width: 100%;" 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="请输入原料材质" :disabled="readonly">
</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">
<MemoInput storageKey="coatingType" 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>
<el-form v-if="form.coilId" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="质量状态" prop="qualityStatus">
<el-select v-model="form.qualityStatus" placeholder="请选择质量状态" style="width: 100%">
<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%">
<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">
<memo-input v-model="form.packingStatus" placeholder="请输入原料材质" storageKey="packingStatus">
</memo-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%">
<el-option label="裸包" value="裸包" />
<el-option label="普包" value="普包" />
<el-option label="简包" value="简包" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div style="display: flex; justify-content: center; gap: 10px;">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</div>
</el-col>
<el-col :span="12">
<div class="section-card">
<!-- 入库记录 -->
<div class="section-header">
<h3 class="section-title">打包记录</h3>
<el-button size="mini" icon="el-icon-refresh" @click="getList">刷新</el-button>
</div>
<el-form inline class="query-form">
<el-form-item label="钢卷号" prop="currentCoilNo">
<el-input v-model="queryForm.currentCoilNo" placeholder="请输入钢卷号" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getList">查询</el-button>
</el-form-item>
</el-form>
<!-- 待操作卡片列表 -->
<div class="card-grid-container">
<div v-if="pendingActions.length === 0" class="empty-state">
<i class="el-icon-document"></i>
<p>暂无打包记录</p>
</div>
<div v-for="(item, index) in pendingActions" :key="item.actionId || index" class="action-card" :class="{
'urgent-card': item.priority === 2,
'important-card': item.priority === 1
}">
<div class="card-header">
<current-coil-no :current-coil-no="item.currentCoilNo"></current-coil-no>
</div>
<div class="card-body">
<div class="info-list">
<div class="info-item">
<span class="info-label">创建人</span>
<span class="info-value">{{ item.createBy || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">创建时间</span>
<span class="info-value">{{ parseTime(item.createTime, '{m}-{d} {h}:{i}') || '—' }}</span>
</div>
</div>
</div>
</div>
</div>
<Pagination v-show="total > 0" :total="total" :page.sync="pagination.currentPage"
:limit.sync="pagination.pageSize" @pagination="getList" />
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import { updateMaterialCoilSimple, getMaterialCoil } from '@/api/wms/coil'
import { listPendingAction, addPendingAction } from '@/api/wms/pendingAction'
import MaterialSelect from "@/components/KLPService/MaterialSelect";
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
import ProductSelect from "@/components/KLPService/ProductSelect";
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
import CoilSelector from "@/components/CoilSelector";
import MemoInput from "@/components/MemoInput";
// 键值为[400, 500), 不包含在字典中但后续可以加入的特殊操作这类操作录入后会立刻完成例如入库401和打包405
export default {
components: {
MaterialSelect,
ActualWarehouseSelect,
WarehouseSelect,
ProductSelect,
RawMaterialSelect,
CoilSelector,
MemoInput
},
dicts: ['coil_quality_status'],
data() {
return {
pendingActions: [],
// 表单参数
form: {},
// 钢卷选择器筛选参数
coilFilters: {
dataType: 1,
status: 0,
},
coilSelectorVisible: false,
loading: false,
buttonLoading: false,
queryForm: {
currentCoilNo: null,
},
// 分页参数
pagination: {
currentPage: 1,
pageSize: 10,
},
total: 0,
formLoading: false,
// 表单校验
rules: {
// enterCoilNo: [
// { required: true, message: "入场钢卷号不能为空", trigger: "blur" }
// ],
// currentCoilNo: [
// { required: true, message: "当前钢卷号不能为空", trigger: "blur" }
// ],
// itemId: [
// { required: true, message: "物品ID不能为空", trigger: "blur" }
// ],
// itemType: [
// { required: true, message: "物品类型不能为空", trigger: "change" }
// ],
// // 净重和毛重
// netWeight: [
// { required: true, message: "净重不能为空", trigger: "blur" }
// ],
// grossWeight: [
// { required: true, message: "毛重不能为空", trigger: "blur" }
// ],
},
}
},
mounted() {
this.getList()
},
computed: {
// 动态显示标签
getItemLabel() {
if (this.form.materialType === '成品') {
return '产品类型';
} else if (this.form.materialType === '原料') {
return '原料类型';
}
return '物品类型';
},
},
methods: {
/** 显示钢卷选择器 */
showCoilSelector() {
this.coilSelectorVisible = true;
},
// 处理材料类型变化
handleMaterialTypeChange(value) {
// 清空物品选择
this.form.itemId = null;
// 根据材料类型设置物品类型
if (value === '成品') {
this.form.itemType = 'product';
} else if (value === '原料') {
this.form.itemType = 'raw_material';
}
},
handleItemChange(item) {
// this.form = item;
this.formLoading = true
getMaterialCoil(item.coilId).then(res => {
this.form = res.data
this.formLoading = false
})
// console.log(item)
},
getList() {
// 获取打包历史
this.loading = true
listPendingAction({ actionType: 405, ...this.pagination, ...this.queryForm }).then(res => {
this.pendingActions = res.rows
this.total = res.total
this.loading = false
})
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
updateMaterialCoilSimple(this.form).then(_ => {
addPendingAction({
actionType: 405,
currentCoilNo: this.form.currentCoilNo,
coilId: this.form.coilId,
sourceType: 'manual',
priority: 0,
remark: this.form.remark,
actionStatus: 2,
}).then(res => {
this.$modal.msgSuccess("打包成功");
this.$refs.form.resetFields();
this.form = {}
this.getList()
})
}).finally(() => {
this.buttonLoading = false;
});
}
});
},
// 取消操作
cancel() {
this.form = {};
this.$refs.form.resetFields();
this.buttonLoading = 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>