Files
klp-oa/klp-ui/src/views/wms/coil/do/warehousing.vue
砂糖 f2b754126c feat(UI组件): 重构产品与原材料选择组件样式和交互
优化产品选择(ProductSelect)和原材料选择(RawMaterialSelect)组件的UI样式和交互逻辑:
1. 将触发按钮改为输入框样式,提升视觉一致性
2. 简化卡片布局,移除冗余的选择按钮
3. 优化选中状态显示,增加规格和材质信息
4. 调整表单样式,减小字体大小和间距
5. 更新空状态提示文案为"暂无发货记录"和"暂无入库记录"
6. 在package.json中添加volta配置指定node版本
2025-11-20 11:27:47 +08:00

681 lines
18 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">
<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 />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="班组" prop="team">
<el-input v-model="form.team" 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-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 v-if="form.materialType === '成品'">
<el-col :span="12">
<el-form-item v-if="form.materialType === '成品'" label="质量状态" prop="qualityStatus">
<el-input v-model="form.qualityStatus" placeholder="请输入质量状态" :disabled="readonly">
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.materialType === '成品'" label="切边要求" prop="trimmingRequirement">
<el-input v-model="form.trimmingRequirement" placeholder="请输入切边要求" :disabled="readonly">
</el-input>
</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-input v-model="form.packagingRequirement" placeholder="请输入包装要求" :disabled="readonly">
</el-input>
</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-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">
<!-- 入库记录 -->
<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 v-loading="actionLoading" 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 { addMaterialCoil } 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 { Pagination } from 'element-ui';
// 键值为[400, 500), 不包含在字典中但后续可以加入的特殊操作这类操作录入后会立刻完成例如入库401和发货402
export default {
components: {
MaterialSelect,
ActualWarehouseSelect,
WarehouseSelect,
ProductSelect,
RawMaterialSelect,
},
data() {
return {
pendingActions: [],
// 表单参数
form: {},
loading: false,
buttonLoading: false,
queryForm: {
currentCoilNo: null,
},
// 分页参数
pagination: {
currentPage: 1,
pageSize: 10,
},
total: 0,
// 表单校验
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: {
// 处理材料类型变化
handleMaterialTypeChange(value) {
// 清空物品选择
this.form.itemId = null;
// 根据材料类型设置物品类型
if (value === '成品') {
this.form.itemType = 'product';
} else if (value === '原料' || value === '废品') {
this.form.itemType = 'raw_material';
}
},
getList() {
// 获取入库历史
this.loading = true
listPendingAction({ actionType: 401, ...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;
addMaterialCoil(this.form).then(response => {
addPendingAction({
actionType: 401,
currentCoilNo: this.form.currentCoilNo,
sourceType: 'manual',
coilId: response.data.coilId,
priority: 0,
remark: this.form.remark,
actionStatus: 2,
}).then(res => {
this.$modal.msgSuccess("入库成功");
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>