439 lines
16 KiB
Vue
439 lines
16 KiB
Vue
<template>
|
||
<div class="app-container">
|
||
<el-row :gutter="20">
|
||
<!-- 左侧:打包表单和明细 -->
|
||
<el-col :span="15">
|
||
<div class="section-card">
|
||
<div class="section-header">
|
||
<h3 class="section-title">创建打包单据</h3>
|
||
<div class="header-actions">
|
||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">保存单据</el-button>
|
||
<el-button @click="resetForm">重置</el-button>
|
||
<coil-selector dialog-width="1200px" :use-trigger="true" multiple :multiple="true" :filters="coilFilters"
|
||
:disableO="true" @confirm="handleBatchAddCoil">
|
||
<el-button type="primary" plain icon="el-icon-plus" size="small">批量添加钢卷</el-button>
|
||
</coil-selector>
|
||
</div>
|
||
</div>
|
||
|
||
<el-form ref="form" :model="form" :rules="rules" label-width="100px" style="margin-bottom: 20px;">
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-form-item label="单据号" prop="packingNo">
|
||
<el-input v-model="form.packingNo" placeholder="系统自动生成" disabled />
|
||
</el-form-item>
|
||
<el-form-item label="批次号" prop="batchNo">
|
||
<el-input v-model="form.batchNo" placeholder="请输入批次号" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="销售员" prop="saleName">
|
||
<el-select v-model="form.saleName" placeholder="请选择销售名称" clearable filterable>
|
||
<el-option v-for="item in dict.type.wip_pack_saleman" :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="packingTime">
|
||
<el-date-picker v-model="form.packingTime" type="datetime" placeholder="选择打包时间"
|
||
value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%" />
|
||
</el-form-item>
|
||
<el-form-item label="操作人" prop="packingBy">
|
||
<el-input v-model="form.packingBy" placeholder="请输入操作人" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="备注" prop="remark">
|
||
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</el-form>
|
||
|
||
<div class="section-header" style="margin-top: 20px;">
|
||
<h3 class="section-title">打包明细</h3>
|
||
</div>
|
||
|
||
<el-table v-loading="detailLoading" :data="detailList" border style="width: 100%" max-height="400">
|
||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||
<el-table-column label="钢卷号" align="center" prop="coilNo" min-width="120">
|
||
<template slot-scope="scope">
|
||
<current-coil-no :current-coil-no="scope.row.coilNo" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="产品类型" align="center" width="250">
|
||
<template slot-scope="scope">
|
||
<ProductInfo v-if="scope.row.itemType == 'product'" :product="scope.row" />
|
||
<RawMaterialInfo v-else-if="scope.row.itemType === 'raw_material'" :material="scope.row" />
|
||
</template>
|
||
</el-table-column>
|
||
<!-- <el-table-column label="品名" align="center" prop="itemName" min-width="100" />
|
||
<el-table-column label="规格" align="center" prop="specification" min-width="120" show-overflow-tooltip />
|
||
<el-table-column label="材质" align="center" prop="material" min-width="80" /> -->
|
||
<el-table-column label="重量" align="center" prop="coilNetWeight" width="80">
|
||
<template slot-scope="scope">{{ scope.row.coilNetWeight }}t</template>
|
||
</el-table-column>
|
||
<!-- <el-table-column label="销售名称" align="center" prop="saleName" width="140">
|
||
<template slot-scope="scope">
|
||
<el-select v-model="scope.row.saleName" placeholder="请选择销售名称">
|
||
<el-option v-for="item in dict.type.wip_pack_saleman" :key="item.value" :label="item.label" :value="item.value" />
|
||
</el-select>
|
||
</template>
|
||
</el-table-column> -->
|
||
<el-table-column label="打包前位置" align="center" prop="fromWarehouseName" min-width="120"
|
||
show-overflow-tooltip />
|
||
<el-table-column label="操作" align="center" width="100">
|
||
<template slot-scope="scope">
|
||
<template v-if="scope.row.editing">
|
||
<el-button size="mini" type="text" @click="handleSaveDetail(scope.row)">保存</el-button>
|
||
<el-button size="mini" type="text" @click="scope.row.editing = false">取消</el-button>
|
||
</template>
|
||
<template v-else>
|
||
<el-button size="mini" type="text" @click="handleDeleteDetail(scope.row)">删除</el-button>
|
||
</template>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div v-if="detailList.length > 0" class="detail-summary">
|
||
<el-descriptions :column="3" size="small" border>
|
||
<el-descriptions-item label="总卷数">
|
||
{{ detailList.length }} 卷
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="总重量">
|
||
{{ totalWeight }} 吨
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
</div>
|
||
</el-col>
|
||
|
||
<!-- 右侧:最近创建的打包单据 -->
|
||
<el-col :span="9">
|
||
<div class="section-card">
|
||
<div class="section-header">
|
||
<h3 class="section-title">最近创建的单据</h3>
|
||
<el-button size="mini" icon="el-icon-refresh" @click="getRecentList">刷新</el-button>
|
||
</div>
|
||
<el-table v-loading="recentLoading" :data="recentList" border style="width: 100%">
|
||
<el-table-column label="单据号" align="center" prop="packingNo" show-overflow-tooltip />
|
||
<el-table-column label="批次号" align="center" prop="batchNo" show-overflow-tooltip />
|
||
<el-table-column label="打包日期" align="center" prop="packingTime" />
|
||
<el-table-column label="卷数" align="center" prop="coilCount" width="60" />
|
||
<el-table-column label="总重" align="center" prop="totalNetWeight" width="80">
|
||
<template slot-scope="scope">{{ scope.row.totalNetWeight }}t</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { addPacking, updatePacking, listPacking, listPackingDetail, updatePackingDetail, delPackingDetail, batchAddPackingDetail, createPacking } from '@/api/wms/packing';
|
||
import CoilSelector from '@/components/CoilSelector';
|
||
import ProductInfo from "@/components/KLPService/Renderer/ProductInfo";
|
||
import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
|
||
|
||
export default {
|
||
name: 'PackingCreate',
|
||
dicts: [],
|
||
components: {
|
||
CoilSelector,
|
||
ProductInfo,
|
||
RawMaterialInfo
|
||
},
|
||
dicts: ['wip_pack_saleman'],
|
||
data() {
|
||
return {
|
||
// 表单参数
|
||
form: {
|
||
packingNo: '',
|
||
batchNo: '',
|
||
packingDate: '',
|
||
team: '',
|
||
packingBy: '',
|
||
remark: ''
|
||
},
|
||
// 当前正在编辑的打包单据ID
|
||
currentPackingId: null,
|
||
// 打包明细列表
|
||
detailList: [],
|
||
// 最近创建的单据列表
|
||
recentList: [],
|
||
// 按钮loading
|
||
buttonLoading: false,
|
||
// 明细loading
|
||
detailLoading: false,
|
||
// 最近列表loading
|
||
recentLoading: false,
|
||
// 表单校验
|
||
rules: {
|
||
batchNo: [
|
||
{ required: true, message: '批次号不能为空', trigger: 'blur' }
|
||
],
|
||
packingDate: [
|
||
{ required: true, message: '打包日期不能为空', trigger: 'change' }
|
||
]
|
||
},
|
||
// 钢卷选择器筛选参数
|
||
coilFilters: {
|
||
dataType: 1,
|
||
status: 0,
|
||
selectType: 'product',
|
||
excludePacked: true
|
||
}
|
||
};
|
||
},
|
||
computed: {
|
||
// 总重量
|
||
totalWeight() {
|
||
return this.detailList.reduce((acc, item) => acc + Number(item.coilNetWeight || 0), 0).toFixed(3);
|
||
},
|
||
// 已填位置的明细数量
|
||
filledPositionCount() {
|
||
return this.detailList.filter(item => item.afterPosition).length;
|
||
}
|
||
},
|
||
created() {
|
||
// 默认设置为今天
|
||
this.form.packingDate = this.formatDate(new Date());
|
||
// 设置打包时间默认值为当前时间
|
||
const now = new Date();
|
||
const year = now.getFullYear();
|
||
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||
const day = String(now.getDate()).padStart(2, '0');
|
||
const hour = String(now.getHours()).padStart(2, '0');
|
||
const minute = String(now.getMinutes()).padStart(2, '0');
|
||
const second = String(now.getSeconds()).padStart(2, '0');
|
||
this.form.packingTime = `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
||
// 自动生成单据号和批次号,格式为yyyyMMddHHmm
|
||
const code = `${year}${month}${day}${hour}${minute}`;
|
||
this.form.packingNo = code;
|
||
this.form.batchNo = code;
|
||
// 设置操作人默认值为当前登录用户
|
||
this.form.packingBy = this.$store.getters.nickName;
|
||
this.getRecentList();
|
||
},
|
||
methods: {
|
||
/** 格式化日期 */
|
||
formatDate(date) {
|
||
const y = date.getFullYear();
|
||
const m = String(date.getMonth() + 1).padStart(2, '0');
|
||
const d = String(date.getDate()).padStart(2, '0');
|
||
return `${y}-${m}-${d}`;
|
||
},
|
||
/** 提交表单 */
|
||
submitForm() {
|
||
this.$refs['form'].validate(valid => {
|
||
if (valid) {
|
||
if (this.detailList.length === 0) {
|
||
this.$modal.msgWarning('请添加打包明细');
|
||
return;
|
||
}
|
||
this.buttonLoading = true;
|
||
const data = {
|
||
...this.form,
|
||
totalNetWeight: this.totalWeight,
|
||
details: this.detailList
|
||
};
|
||
createPacking(data).then(response => {
|
||
this.$modal.msgSuccess('创建成功');
|
||
this.getRecentList();
|
||
this.resetForm();
|
||
}).finally(() => {
|
||
this.buttonLoading = false;
|
||
});
|
||
}
|
||
});
|
||
},
|
||
/** 重置表单 */
|
||
resetForm() {
|
||
// 自动生成新的单据号和批次号,格式为yyyyMMddHHmm
|
||
const now = new Date();
|
||
const year = now.getFullYear();
|
||
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||
const day = String(now.getDate()).padStart(2, '0');
|
||
const hour = String(now.getHours()).padStart(2, '0');
|
||
const minute = String(now.getMinutes()).padStart(2, '0');
|
||
const second = String(now.getSeconds()).padStart(2, '0');
|
||
const code = `${year}${month}${day}${hour}${minute}`;
|
||
|
||
this.form = {
|
||
packingNo: code,
|
||
batchNo: code,
|
||
packingDate: this.formatDate(new Date()),
|
||
packingTime: `${year}-${month}-${day} ${hour}:${minute}:${second}`,
|
||
packingBy: this.$store.getters.nickName,
|
||
remark: ''
|
||
};
|
||
this.currentPackingId = null;
|
||
this.detailList = [];
|
||
this.$refs.form.resetFields();
|
||
},
|
||
/** 批量添加钢卷 */
|
||
handleBatchAddCoil(coils) {
|
||
const newCoils = coils.map(coil => ({
|
||
coilId: coil.coilId,
|
||
coilNo: coil.currentCoilNo,
|
||
itemName: coil.itemName,
|
||
specification: coil.specification,
|
||
material: coil.material,
|
||
coilNetWeight: coil.netWeight || '',
|
||
coilGrossWeight: coil.grossWeight || '0.000',
|
||
fromWarehouseId: coil.warehouseId || '',
|
||
fromWarehouseName: coil.warehouseName || '',
|
||
itemType: coil.itemType || '',
|
||
itemId: coil.itemId || '',
|
||
// beforePosition: coil.actualWarehouseName || '',
|
||
toWarehouseId: '2035892198703349761',
|
||
toWarehouseName: '打包待发货'
|
||
}));
|
||
this.detailList = [...this.detailList, ...newCoils];
|
||
this.$modal.msgSuccess('添加成功');
|
||
},
|
||
/** 获取明细列表 */
|
||
getDetailList() {
|
||
if (!this.currentPackingId) return;
|
||
this.detailLoading = true;
|
||
listPackingDetail({ packingId: this.currentPackingId }).then(response => {
|
||
this.detailList = response.rows || [];
|
||
}).finally(() => {
|
||
this.detailLoading = false;
|
||
});
|
||
},
|
||
/** 编辑明细 */
|
||
handleEditDetail(row) {
|
||
this.$set(row, 'editing', true);
|
||
this.$set(row, 'afterPositionBackup', row.afterPosition);
|
||
},
|
||
/** 保存明细修改 */
|
||
handleSaveDetail(row) {
|
||
this.detailLoading = true;
|
||
updatePackingDetail(row).then(response => {
|
||
this.$modal.msgSuccess('保存成功');
|
||
row.editing = false;
|
||
this.getDetailList();
|
||
}).catch(() => {
|
||
this.detailLoading = false;
|
||
});
|
||
},
|
||
/** 删除明细 */
|
||
handleDeleteDetail(row) {
|
||
// 前端删除,根据coilId删除所有相关明细
|
||
this.detailList = this.detailList.filter(item => item.coilId !== row.coilId);
|
||
// this.$modal.confirm('确认删除该钢卷明细吗?').then(() => {
|
||
// return delPackingDetail(row.detailId);
|
||
// }).then(() => {
|
||
// this.$modal.msgSuccess('删除成功');
|
||
// this.getDetailList();
|
||
// }).catch(() => { });
|
||
},
|
||
/** 获取最近创建的单据列表 */
|
||
getRecentList() {
|
||
this.recentLoading = true;
|
||
listPacking({
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
orderByColumn: 'createTime',
|
||
isAsc: 'desc'
|
||
}).then(response => {
|
||
this.recentList = response.rows || [];
|
||
}).finally(() => {
|
||
this.recentLoading = false;
|
||
});
|
||
},
|
||
/** 查看单据详情 */
|
||
handleViewDetail(row) {
|
||
this.$router.push({
|
||
path: '/wms/packing/record',
|
||
query: { packingId: row.packingId }
|
||
});
|
||
},
|
||
/** 继续编辑单据 */
|
||
handleContinueEdit(row) {
|
||
this.currentPackingId = row.packingId;
|
||
this.form.packingNo = row.packingNo;
|
||
this.form.batchNo = row.batchNo;
|
||
this.form.packingDate = row.packingDate;
|
||
this.form.team = row.team;
|
||
this.form.operator = row.operator;
|
||
this.form.remark = row.remark;
|
||
this.getDetailList();
|
||
this.$message.success('已加载单据,请继续编辑');
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.app-container {
|
||
padding: 20px;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
|
||
.header-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
|
||
.tip-text {
|
||
font-size: 13px;
|
||
color: #909399;
|
||
}
|
||
}
|
||
}
|
||
|
||
.form-footer {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 12px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.empty-tips {
|
||
text-align: center;
|
||
padding: 60px 20px;
|
||
color: #909399;
|
||
|
||
i {
|
||
font-size: 48px;
|
||
margin-bottom: 16px;
|
||
display: block;
|
||
color: #e6a23c;
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
.detail-summary {
|
||
margin-top: 16px;
|
||
padding: 12px;
|
||
background-color: #f5f7fa;
|
||
border-radius: 4px;
|
||
}
|
||
</style>
|