Files
klp-oa/klp-ui/src/views/wms/coil/do/packing.vue
砂糖 707761fe8d feat(wms): 将班组输入框改为下拉选择并添加编辑功能
- 将多个页面中的班组输入框改为下拉选择框,提供甲、乙两个选项
- 在入库页面添加钢卷信息编辑功能,支持修改钢卷号、库位、班组等信息
- 调整入库页面布局,优化表单字段显示
- 添加批量打印标签的权限控制
2026-01-10 11:04:52 +08:00

760 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-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 v-if="form.materialType === '成品'">
<el-col :span="12">
<el-form-item v-if="form.materialType === '成品'" label="质量状态" prop="qualityStatus">
<el-select v-model="form.qualityStatus" placeholder="请选择质量状态" style="width: 100%"
:disabled="readonly">
<el-option label="A+" value="A+" />
<el-option label="A" value="A" />
<el-option label="A-" value="A-" />
<el-option label="B+" value="B+" />
<el-option label="B" value="B" />
<el-option label="B-" value="B-" />
<el-option label="C+" value="C+" />
<el-option label="C" value="C" />
<el-option label="C-" value="C-" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.materialType === '成品'" 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 v-if="form.materialType === '成品'" 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 v-if="form.materialType === '成品'" 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="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">
<memo-input v-model="form.qualityStatus" placeholder="请输入质量状态" storageKey="qualityStatus">
</memo-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="切边要求" prop="trimmingRequirement">
<memo-input v-model="form.trimmingRequirement" placeholder="请输入切边要求" storageKey="trimmingRequirement">
</memo-input>
</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">
<memo-input v-model="form.packagingRequirement" placeholder="请输入包装要求"
storageKey="packagingRequirement">
</memo-input>
</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">
<el-tag type="info" size="small" class="coil-no-tag">{{ item.currentCoilNo }}</el-tag>
</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 { updateMaterialCoil, 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
},
data() {
return {
pendingActions: [],
// 表单参数
form: {},
// 钢卷选择器筛选参数
coilFilters: {
dataType: 1,
},
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 === '原料' || 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 === '原料' || 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;
updateMaterialCoil(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>