You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1744 lines
51 KiB
1744 lines
51 KiB
<template>
|
|
<div class="packing-detail-tab">
|
|
<!-- 批量编辑按钮 -->
|
|
<div class="batch-edit-toolbar" v-if="showActions">
|
|
<el-button type="primary" size="small" icon="el-icon-edit" @click="openBatchEditDialog">
|
|
批量编辑
|
|
</el-button>
|
|
</div>
|
|
|
|
<el-table
|
|
:data="dataListBoxes"
|
|
:height="height"
|
|
border
|
|
v-loading="dataListLoading"
|
|
style="width: 100%;"
|
|
:expand-row-keys="expandedBoxRows"
|
|
:row-key="getBoxRowKey"
|
|
@expand-change="handleBoxExpand"
|
|
show-summary
|
|
:summary-method="getSummaries">
|
|
<el-table-column type="expand">
|
|
<template slot-scope="props">
|
|
<!-- 加载状态 -->
|
|
<div v-if="props.row.loading" class="expand-loading">
|
|
<i class="el-icon-loading"></i>
|
|
<span>正在加载明细数据...</span>
|
|
</div>
|
|
|
|
<!-- 明细内容区域 -->
|
|
<div v-else class="expand-detail-container">
|
|
<!-- 明细表格 -->
|
|
<el-table
|
|
v-if="props.row.palletDetails && props.row.palletDetails.length > 0"
|
|
:data="props.row.palletDetails"
|
|
:max-height="300"
|
|
size="mini"
|
|
stripe
|
|
class="expand-detail-table">
|
|
<el-table-column
|
|
v-for="(item,index) in columnList3" :key="index"
|
|
:sortable="item.columnSortable"
|
|
:prop="item.columnProp"
|
|
:header-align="item.headerAlign"
|
|
:show-overflow-tooltip="item.showOverflowTooltip"
|
|
:align="item.align"
|
|
:min-width="item.columnWidth"
|
|
:label="item.columnLabel">
|
|
<template slot-scope="scope">
|
|
<span v-if="!item.columnHidden">
|
|
{{ formatDetailValue(scope.row[item.columnProp], item.columnProp) }}
|
|
</span>
|
|
<span v-if="item.columnImage">
|
|
<img :src="scope.row[item.columnProp]" style="width: 100px; height: 80px"/>
|
|
</span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<!-- 明细操作列 -->
|
|
<el-table-column
|
|
label="操作"
|
|
width="120"
|
|
align="center"
|
|
fixed="right"
|
|
v-if="showActions">
|
|
<template slot-scope="scope">
|
|
<a type="text" size="small" @click="handleEditDetail(scope.row, props.row)">修改</a>
|
|
<a type="text" size="small" @click="handleDeleteDetail(scope.row, props.row)">删除</a>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<!-- 空数据状态 -->
|
|
<div v-else class="expand-empty-state">
|
|
<i class="el-icon-box"></i>
|
|
<p>暂无明细数据</p>
|
|
<span>该栈板下暂时没有装箱明细信息</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
v-for="(item,index) in columnListBoxes" :key="index"
|
|
:sortable="item.columnSortable"
|
|
:prop="item.columnProp"
|
|
:header-align="item.headerAlign"
|
|
:show-overflow-tooltip="item.showOverflowTooltip"
|
|
:align="item.align"
|
|
:fixed="item.fixed==''?false:item.fixed"
|
|
:min-width="item.columnWidth"
|
|
:label="item.columnLabel">
|
|
<template slot-scope="scope">
|
|
<span v-if="!item.columnHidden"> {{ scope.row[item.columnProp] }}</span>
|
|
<span v-if="item.columnImage"><img :src="scope.row[item.columnProp]"
|
|
style="width: 100px; height: 80px"/></span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<!-- 主表格操作列 -->
|
|
<el-table-column
|
|
label="操作"
|
|
width="120"
|
|
align="center"
|
|
fixed="right"
|
|
v-if="showActions">
|
|
<template slot-scope="scope">
|
|
<a type="text" size="small" @click="handleEditBox(scope.row)">修改</a>
|
|
<a type="text" size="small" @click="handleDeleteBox(scope.row)">删除</a>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<!-- 修改箱信息弹窗 -->
|
|
<el-dialog
|
|
title="修改箱信息"
|
|
:visible.sync="editBoxDialogVisible"
|
|
width="200px"
|
|
:close-on-click-modal="false">
|
|
<el-form :model="editBoxForm" ref="editBoxForm" label-position="top" label-width="100px">
|
|
<el-row :gutter="20">
|
|
<el-col :span="24">
|
|
<el-form-item label="箱数" prop="box_qty">
|
|
<el-input v-model="editBoxForm.box_qty" @input="onBoxQtyChange" :min="1" :precision="0" style="width: 100%"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="24">
|
|
<el-form-item label="毛重" prop="grossWeight">
|
|
<el-input v-model="editBoxForm.grossWeight" @input="onGrossWeightChange" :min="0" :precision="2" style="width: 100%"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="24">
|
|
<el-form-item label="净重" prop="netWeight">
|
|
<el-input v-model="editBoxForm.netWeight" @input="onNetWeightChange" :min="0" :precision="2" style="width: 100%"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
</el-form>
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="editBoxDialogVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="submitEditBox" >确定</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
|
|
<!-- 修改明细弹窗 -->
|
|
<el-dialog
|
|
title="修改明细信息"
|
|
:visible.sync="editDetailDialogVisible"
|
|
width="400px"
|
|
:close-on-click-modal="false">
|
|
<el-form :model="editDetailForm" ref="editDetailForm" label-position="top" label-width="100px">
|
|
<el-row :gutter="20">
|
|
<el-col :span="12">
|
|
<el-form-item label="PO" prop="poNo">
|
|
<el-input v-model="editDetailForm.poNo" disabled></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="PN" prop="pn">
|
|
<el-input v-model="editDetailForm.pn" disabled></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="数量" prop="qty">
|
|
<el-input v-model="editDetailForm.qty" style="width: 100%"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="Rolls" prop="rolls">
|
|
<el-input v-model="editDetailForm.rolls" style="width: 100%"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
</el-form>
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="editDetailDialogVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="submitEditDetail" >确定</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
|
|
<!-- 批量编辑弹窗 -->
|
|
<el-dialog
|
|
title="批量编辑装箱明细"
|
|
:visible.sync="batchEditDialogVisible"
|
|
width="60%"
|
|
top="5vh"
|
|
custom-class="batch-edit-dialog"
|
|
:close-on-click-modal="false"
|
|
@open="loadBatchEditData">
|
|
<div class="batch-edit-container" v-loading="batchEditLoading">
|
|
<!-- 操作提示 -->
|
|
<div class="batch-edit-tips">
|
|
<el-alert
|
|
type="info"
|
|
:closable="false"
|
|
show-icon>
|
|
<template slot="title">
|
|
<span>直接在表格中编辑数据,修改后点击"保存所有修改"按钮提交</span>
|
|
<span v-if="batchEditModifiedCount > 0" class="modified-count">
|
|
(已修改 <b>{{ batchEditModifiedCount }}</b> 处)
|
|
</span>
|
|
</template>
|
|
</el-alert>
|
|
</div>
|
|
|
|
<!-- 行合并表格 -->
|
|
<el-table
|
|
:data="batchEditTableData"
|
|
:span-method="batchEditSpanMethod"
|
|
border
|
|
size="small"
|
|
max-height="60vh"
|
|
style="width: 100%"
|
|
:row-class-name="getBatchEditRowClassName"
|
|
:header-cell-style="{background:'#f5f7fa', color:'#606266', fontWeight:'600'}">
|
|
|
|
<!-- Box信息列(会合并) -->
|
|
<el-table-column label="序号" prop="item_no" width="60" align="center">
|
|
<template slot-scope="scope">
|
|
<span class="box-info-cell">{{ scope.row.item_no }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column label="箱数" prop="box_qty" width="80" align="center">
|
|
<template slot-scope="scope">
|
|
<el-input
|
|
v-model="scope.row.box_qty"
|
|
size="mini"
|
|
type="number"
|
|
:class="{'modified-input': isBoxFieldModified(scope.row, 'box_qty')}"
|
|
@input="onBatchBoxQtyInput(scope.row)"
|
|
@change="onBatchBoxFieldChange(scope.row, 'box_qty')">
|
|
</el-input>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column label="毛重" prop="grossWeight" width="100" align="center">
|
|
<template slot-scope="scope">
|
|
<el-input
|
|
v-model="scope.row.grossWeight"
|
|
size="mini"
|
|
type="number"
|
|
:class="{'modified-input': isBoxFieldModified(scope.row, 'grossWeight')}"
|
|
@input="onBatchGrossWeightInput(scope.row)"
|
|
@change="onBatchBoxFieldChange(scope.row, 'grossWeight')">
|
|
</el-input>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column label="净重" prop="netWeight" width="100" align="center">
|
|
<template slot-scope="scope">
|
|
<el-input
|
|
v-model="scope.row.netWeight"
|
|
size="mini"
|
|
type="number"
|
|
:class="{'modified-input': isBoxFieldModified(scope.row, 'netWeight')}"
|
|
@input="onBatchNetWeightInput(scope.row)"
|
|
@change="onBatchBoxFieldChange(scope.row, 'netWeight')">
|
|
</el-input>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<!-- 明细信息列(不合并) -->
|
|
<el-table-column label="PO" prop="poNo" min-width="120" align="left">
|
|
<template slot-scope="scope">
|
|
<span>{{ scope.row.poNo || '-' }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column label="PN" prop="pn" min-width="120" align="left">
|
|
<template slot-scope="scope">
|
|
<span>{{ scope.row.pn || '-' }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column label="数量" prop="qty" width="100" align="center">
|
|
<template slot-scope="scope">
|
|
<el-input
|
|
v-model="scope.row.qty"
|
|
size="mini"
|
|
type="number"
|
|
:class="{'modified-input': isDetailFieldModified(scope.row, 'qty')}"
|
|
@change="onBatchDetailFieldChange(scope.row, 'qty')">
|
|
</el-input>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column label="Rolls" prop="rolls" width="80" align="center">
|
|
<template slot-scope="scope">
|
|
<el-input
|
|
v-model="scope.row.rolls"
|
|
size="mini"
|
|
type="number"
|
|
:class="{'modified-input': isDetailFieldModified(scope.row, 'rolls')}"
|
|
@change="onBatchDetailFieldChange(scope.row, 'rolls')">
|
|
</el-input>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</div>
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="batchEditDialogVisible = false">取消</el-button>
|
|
<el-button
|
|
type="primary"
|
|
:loading="batchEditSaving"
|
|
:disabled="batchEditModifiedCount === 0"
|
|
@click="saveBatchEdit">
|
|
保存所有修改 ({{ batchEditModifiedCount }})
|
|
</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { selectBoxList, searchCoDelPalletDataNew, updateBoxInfo, deleteBoxInfo, updateDetailInfo, deleteDetailInfo, batchUpdatePackingInfo } from "@/api/ecss/ecss.js"
|
|
|
|
export default {
|
|
name: "PackingDetailTab",
|
|
props: {
|
|
currentRow: {
|
|
type: Object,
|
|
default: () => ({})
|
|
},
|
|
height: {
|
|
type: Number,
|
|
default: 200
|
|
},
|
|
showActions: {
|
|
type: Boolean,
|
|
default: true
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
dataListBoxes: [], // 箱数据列表
|
|
expandedBoxRows: [], // 展开的行
|
|
dataListLoading: false,
|
|
|
|
// 修改箱信息弹窗相关
|
|
editBoxDialogVisible: false,
|
|
editBoxForm: {
|
|
item_no: '',
|
|
box_qty: 1,
|
|
grossWeight: 0,
|
|
netWeight: 0
|
|
},
|
|
editBoxSubmitting: false,
|
|
currentEditBox: null,
|
|
|
|
// 修改明细弹窗相关
|
|
editDetailDialogVisible: false,
|
|
editDetailForm: {
|
|
itemNo: '',
|
|
poNo: '',
|
|
pn: '',
|
|
qty: 1,
|
|
rolls: 0
|
|
},
|
|
editDetailSubmitting: false,
|
|
currentEditDetail: null,
|
|
currentEditBoxForDetail: null,
|
|
|
|
// 批量编辑弹窗相关
|
|
batchEditDialogVisible: false,
|
|
batchEditLoading: false,
|
|
batchEditSaving: false,
|
|
batchEditTableData: [], // 扁平化的表格数据
|
|
batchEditOriginalData: {}, // 原始数据快照(用于对比是否修改)
|
|
batchEditModifiedBoxes: {}, // 修改过的Box记录
|
|
batchEditModifiedDetails: {}, // 修改过的明细记录
|
|
batchEditSpanInfo: [], // 行合并信息
|
|
|
|
// 装箱明细列定义
|
|
columnList3: [
|
|
{
|
|
userId: this.$store.state.user.name,
|
|
functionId: 801002,
|
|
serialNumber: '801002Table3ItemNo',
|
|
tableId: "801002Table3",
|
|
tableName: "装箱明细",
|
|
columnProp: "itemNo",
|
|
headerAlign: "center",
|
|
align: "right",
|
|
columnLabel: "序号",
|
|
columnHidden: false,
|
|
columnImage: false,
|
|
columnSortable: false,
|
|
sortLv: 0,
|
|
status: true,
|
|
fixed: '',
|
|
columnWidth: 40
|
|
},
|
|
{
|
|
userId: this.$store.state.user.name,
|
|
functionId: 801002,
|
|
serialNumber: '801002Table3PoNo',
|
|
tableId: "801002Table3",
|
|
tableName: "装箱明细",
|
|
columnProp: "poNo",
|
|
headerAlign: "center",
|
|
align: "left",
|
|
columnLabel: "PO",
|
|
columnHidden: false,
|
|
columnImage: false,
|
|
columnSortable: false,
|
|
sortLv: 0,
|
|
status: true,
|
|
fixed: '',
|
|
columnWidth: 100
|
|
},
|
|
{
|
|
userId: this.$store.state.user.name,
|
|
functionId: 801002,
|
|
serialNumber: '801002Table3PN',
|
|
tableId: "801002Table3",
|
|
tableName: "装箱明细",
|
|
columnProp: "pn",
|
|
headerAlign: "center",
|
|
align: "left",
|
|
columnLabel: "PN",
|
|
columnHidden: false,
|
|
columnImage: false,
|
|
columnSortable: false,
|
|
sortLv: 0,
|
|
status: true,
|
|
fixed: '',
|
|
columnWidth: 100
|
|
},
|
|
{
|
|
userId: this.$store.state.user.name,
|
|
functionId: 801002,
|
|
serialNumber: '801002Table3Qty',
|
|
tableId: "801002Table3",
|
|
tableName: "装箱明细",
|
|
columnProp: "qty",
|
|
headerAlign: "center",
|
|
align: "right",
|
|
columnLabel: "数量",
|
|
columnHidden: false,
|
|
columnImage: false,
|
|
columnSortable: false,
|
|
sortLv: 0,
|
|
status: true,
|
|
fixed: '',
|
|
columnWidth: 50
|
|
},
|
|
{
|
|
userId: this.$store.state.user.name,
|
|
functionId: 801002,
|
|
serialNumber: '801002Table3Rolls',
|
|
tableId: "801002Table3",
|
|
tableName: "装箱明细",
|
|
columnProp: "rolls",
|
|
headerAlign: "center",
|
|
align: "right",
|
|
columnLabel: "Rolls",
|
|
columnHidden: false,
|
|
columnImage: false,
|
|
columnSortable: false,
|
|
sortLv: 0,
|
|
status: true,
|
|
fixed: '',
|
|
columnWidth: 50
|
|
},
|
|
],
|
|
// 箱数据列定义
|
|
columnListBoxes: [
|
|
{
|
|
userId: this.$store.state.user.name,
|
|
functionId: 801002,
|
|
serialNumber: '801002Table3ItemNo',
|
|
tableId: "801002Table3",
|
|
tableName: "装箱明细",
|
|
columnProp: "item_no",
|
|
headerAlign: "center",
|
|
align: "right",
|
|
columnLabel: "序号",
|
|
columnHidden: false,
|
|
columnImage: false,
|
|
columnSortable: false,
|
|
sortLv: 0,
|
|
status: true,
|
|
fixed: '',
|
|
columnWidth: 40
|
|
},
|
|
{
|
|
userId: this.$store.state.user.name,
|
|
functionId: 801002,
|
|
serialNumber: '801002Table3BoxQty',
|
|
tableId: "801002Table3",
|
|
tableName: "装箱明细",
|
|
columnProp: "box_qty",
|
|
headerAlign: "center",
|
|
align: "right",
|
|
columnLabel: "箱数",
|
|
columnHidden: false,
|
|
columnImage: false,
|
|
columnSortable: false,
|
|
sortLv: 0,
|
|
status: true,
|
|
fixed: '',
|
|
columnWidth: 50
|
|
},
|
|
{
|
|
userId: this.$store.state.user.name,
|
|
functionId: 801002,
|
|
serialNumber: '801002TableGrossWeight',
|
|
tableId: "801002Table3",
|
|
tableName: "装箱明细",
|
|
columnProp: "grossWeight",
|
|
headerAlign: "center",
|
|
align: "right",
|
|
columnLabel: "毛重",
|
|
columnHidden: false,
|
|
columnImage: false,
|
|
columnSortable: false,
|
|
sortLv: 0,
|
|
status: true,
|
|
fixed: '',
|
|
columnWidth: 50
|
|
},
|
|
{
|
|
userId: this.$store.state.user.name,
|
|
functionId: 801002,
|
|
serialNumber: '801002TableNetWeight',
|
|
tableId: "801002Table3",
|
|
tableName: "装箱明细",
|
|
columnProp: "netWeight",
|
|
headerAlign: "center",
|
|
align: "right",
|
|
columnLabel: "净重",
|
|
columnHidden: false,
|
|
columnImage: false,
|
|
columnSortable: false,
|
|
sortLv: 0,
|
|
status: true,
|
|
fixed: '',
|
|
columnWidth: 50
|
|
},
|
|
]
|
|
}
|
|
},
|
|
computed: {
|
|
// 批量编辑修改数量
|
|
batchEditModifiedCount() {
|
|
return Object.keys(this.batchEditModifiedBoxes).length +
|
|
Object.keys(this.batchEditModifiedDetails).length;
|
|
}
|
|
},
|
|
watch: {
|
|
currentRow: {
|
|
handler(newVal) {
|
|
if (newVal && newVal.site) {
|
|
this.loadBoxList();
|
|
}
|
|
},
|
|
deep: true,
|
|
immediate: true
|
|
}
|
|
},
|
|
methods: {
|
|
// 装箱明细相关方法
|
|
loadBoxList() {
|
|
if (!this.currentRow || !this.currentRow.site) {
|
|
this.dataListBoxes = [];
|
|
return;
|
|
}
|
|
|
|
// 清理之前的展开状态
|
|
this.expandedBoxRows = [];
|
|
this.dataListLoading = true;
|
|
|
|
// 获取ecss_CoDelBoxList数据
|
|
selectBoxList(this.currentRow).then(({data}) => {
|
|
if (data && data.code == 0) {
|
|
this.dataListBoxes = data.rows.map(row => ({
|
|
...row,
|
|
palletDetails: [], // 初始化明细数据为空
|
|
loading: false, // 初始化加载状态
|
|
hadDetails: false // 初始化是否有明细标记
|
|
}))
|
|
} else {
|
|
this.dataListBoxes = [];
|
|
}
|
|
}).catch(error => {
|
|
console.error('加载箱数据失败:', error);
|
|
this.dataListBoxes = [];
|
|
}).finally(() => {
|
|
this.dataListLoading = false;
|
|
});
|
|
},
|
|
|
|
// 获取行的唯一标识
|
|
getBoxRowKey(row) {
|
|
// 使用多个字段组合确保唯一性
|
|
return `${row.item_no || ''}_${row.palletRemark || ''}_${row.box_qty || ''}`;
|
|
},
|
|
|
|
// 处理行展开事件
|
|
handleBoxExpand(row, expandedRows) {
|
|
// 判断当前操作是展开还是收起
|
|
const isExpanding = expandedRows.includes(row);
|
|
|
|
if (isExpanding) {
|
|
// 如果是展开操作,则展开所有行
|
|
this.expandAll();
|
|
} else {
|
|
// 如果是收起操作,则收起所有行
|
|
this.collapseAll();
|
|
}
|
|
},
|
|
|
|
// 加载栈板明细数据
|
|
loadPalletDetails(boxRow) {
|
|
if (boxRow.palletDetails && boxRow.palletDetails.length > 0) {
|
|
// 如果已经加载过,直接返回
|
|
return;
|
|
}
|
|
|
|
// 设置加载状态
|
|
this.$set(boxRow, 'loading', true);
|
|
|
|
// 构造查询参数
|
|
let detailParams = {
|
|
site: this.currentRow.site,
|
|
buNo: this.currentRow.buNo,
|
|
delNo: this.currentRow.delNo,
|
|
seqNo: boxRow.item_no,
|
|
palletRemark: boxRow.palletRemark
|
|
};
|
|
|
|
// 调用API获取明细数据
|
|
searchCoDelPalletDataNew(detailParams).then(({data}) => {
|
|
if (data && data.code == 0) {
|
|
// 将明细数据赋值给当前行
|
|
this.$set(boxRow, 'palletDetails', data.rows);
|
|
|
|
// 如果明细为空,且之前有明细数据,说明明细被删除了,需要检查box是否也应该被删除
|
|
if (data.rows.length === 0 && boxRow.hadDetails) {
|
|
// 延迟刷新列表,让后端有时间处理删除逻辑
|
|
setTimeout(() => {
|
|
this.loadBoxList();
|
|
}, 500);
|
|
}
|
|
|
|
// 标记是否有过明细数据
|
|
this.$set(boxRow, 'hadDetails', data.rows.length > 0);
|
|
} else {
|
|
this.$set(boxRow, 'palletDetails', []);
|
|
this.$set(boxRow, 'hadDetails', false);
|
|
}
|
|
}).catch(error => {
|
|
console.error('加载栈板明细数据失败:', error);
|
|
this.$set(boxRow, 'palletDetails', []);
|
|
this.$set(boxRow, 'hadDetails', false);
|
|
}).finally(() => {
|
|
// 清除加载状态
|
|
this.$set(boxRow, 'loading', false);
|
|
});
|
|
},
|
|
|
|
// 格式化明细值显示
|
|
formatDetailValue(value, columnProp) {
|
|
if (value === null || value === undefined || value === '') {
|
|
return '-';
|
|
}
|
|
|
|
// 数字类型格式化
|
|
if (columnProp === 'qty' || columnProp === 'rolls') {
|
|
return parseInt(value).toLocaleString();
|
|
}
|
|
|
|
return value;
|
|
},
|
|
|
|
// 展开所有行
|
|
expandAll() {
|
|
// 获取所有行的key
|
|
this.expandedBoxRows = this.dataListBoxes.map(row => this.getBoxRowKey(row));
|
|
|
|
// 为每个行加载明细数据
|
|
this.dataListBoxes.forEach(row => {
|
|
this.loadPalletDetails(row);
|
|
});
|
|
},
|
|
|
|
// 收起所有行
|
|
collapseAll() {
|
|
this.expandedBoxRows = [];
|
|
},
|
|
|
|
// 刷新数据的公共方法
|
|
refresh() {
|
|
this.loadBoxList();
|
|
},
|
|
|
|
/*
|
|
* 删除逻辑说明:
|
|
* 1. 删除明细时:
|
|
* - 先删除明细数据
|
|
* - 检查该明细所属的box是否还有其他明细
|
|
* - 如果没有明细了,自动删除对应的box
|
|
*
|
|
* 2. 删除box时:
|
|
* - 先检查是否有明细数据
|
|
* - 如果有明细,提示用户并同时删除所有明细和box
|
|
* - 如果没有明细,直接删除box
|
|
*/
|
|
|
|
// 处理修改箱信息
|
|
handleEditBox(boxRow) {
|
|
this.currentEditBox = boxRow;
|
|
this.editBoxForm.item_no = boxRow.item_no;
|
|
this.editBoxForm.box_qty = boxRow.box_qty;
|
|
this.editBoxForm.grossWeight = boxRow.grossWeight;
|
|
this.editBoxForm.netWeight = boxRow.netWeight;
|
|
this.editBoxDialogVisible = true;
|
|
},
|
|
|
|
// 处理删除箱信息
|
|
handleDeleteBox(boxRow) {
|
|
// 直接删除box及其所有明细,无需校验
|
|
this.deleteBoxWithDetails(boxRow);
|
|
},
|
|
|
|
// 删除箱信息(包含明细)
|
|
deleteBoxWithDetails(boxRow) {
|
|
this.$confirm(`确定要删除序号为 ${boxRow.item_no} 的箱信息吗?删除后无法恢复!`, '警告', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
// 构造删除参数
|
|
const deleteParams = {
|
|
site: this.currentRow.site,
|
|
buNo: this.currentRow.buNo,
|
|
delNo: this.currentRow.delNo,
|
|
item_no: boxRow.item_no,
|
|
palletRemark: boxRow.palletRemark
|
|
};
|
|
deleteBoxInfo(deleteParams).then(({data}) => {
|
|
if (data && data.code === 0) {
|
|
this.loadBoxList()
|
|
this.$message({
|
|
message: '操作成功',
|
|
type: 'success',
|
|
duration: 1500,
|
|
onClose: () => {}
|
|
})
|
|
} else {
|
|
this.$alert(data.msg, '错误', {
|
|
confirmButtonText: '确定'
|
|
})
|
|
}
|
|
})
|
|
});
|
|
},
|
|
|
|
// 处理修改明细
|
|
handleEditDetail(detailRow, boxRow) {
|
|
this.currentEditDetail = detailRow;
|
|
this.currentEditBoxForDetail = boxRow;
|
|
this.editDetailForm.itemNo = detailRow.itemNo;
|
|
this.editDetailForm.poNo = detailRow.poNo;
|
|
this.editDetailForm.pn = detailRow.pn;
|
|
this.editDetailForm.qty = detailRow.qty;
|
|
this.editDetailForm.rolls = detailRow.rolls;
|
|
this.editDetailDialogVisible = true;
|
|
},
|
|
|
|
/**
|
|
* 箱数改变时自动计算净重
|
|
* 保持毛重不变,重新计算净重
|
|
* 计算公式:净重 = 毛重 - box_qty/2
|
|
*/
|
|
onBoxQtyChange(value) {
|
|
// 防止循环触发,使用标志位
|
|
if (this._isCalculating) {
|
|
return;
|
|
}
|
|
|
|
this._isCalculating = true;
|
|
|
|
try {
|
|
const boxQty = parseFloat(value) || 0;
|
|
const grossWeight = parseFloat(this.editBoxForm.grossWeight) || 0;
|
|
|
|
// 计算净重:净重 = 毛重 - box_qty/2
|
|
const netWeight = grossWeight - (boxQty / 2);
|
|
|
|
// 保留2位小数
|
|
this.editBoxForm.netWeight = netWeight.toFixed(2);
|
|
} finally {
|
|
this._isCalculating = false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 毛重改变时自动计算净重
|
|
* 计算公式:净重 = 毛重 - box_qty/2
|
|
*/
|
|
onGrossWeightChange(value) {
|
|
// 防止循环触发,使用标志位
|
|
if (this._isCalculating) {
|
|
return;
|
|
}
|
|
|
|
this._isCalculating = true;
|
|
|
|
try {
|
|
const grossWeight = parseFloat(value) || 0;
|
|
const boxQty = parseFloat(this.editBoxForm.box_qty) || 0;
|
|
|
|
// 计算净重:净重 = 毛重 - box_qty/2
|
|
const netWeight = grossWeight - (boxQty / 2);
|
|
|
|
// 保留2位小数
|
|
this.editBoxForm.netWeight = netWeight.toFixed(2);
|
|
} finally {
|
|
this._isCalculating = false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 净重改变时自动计算毛重
|
|
* 反向计算公式:毛重 = 净重 + box_qty/2
|
|
*/
|
|
onNetWeightChange(value) {
|
|
// 防止循环触发,使用标志位
|
|
if (this._isCalculating) {
|
|
return;
|
|
}
|
|
|
|
this._isCalculating = true;
|
|
|
|
try {
|
|
const netWeight = parseFloat(value) || 0;
|
|
const boxQty = parseFloat(this.editBoxForm.box_qty) || 0;
|
|
|
|
// 反向计算毛重:毛重 = 净重 + box_qty/2
|
|
const grossWeight = netWeight + (boxQty / 2);
|
|
|
|
// 保留2位小数
|
|
this.editBoxForm.grossWeight = grossWeight.toFixed(2);
|
|
} finally {
|
|
this._isCalculating = false;
|
|
}
|
|
},
|
|
|
|
// 提交修改箱信息
|
|
submitEditBox() {
|
|
this.$refs.editBoxForm.validate(valid => {
|
|
if (valid) {
|
|
this.editBoxSubmitting = true;
|
|
|
|
// 构造更新参数
|
|
const updateParams = {
|
|
site: this.currentRow.site,
|
|
buNo: this.currentRow.buNo,
|
|
delNo: this.currentRow.delNo,
|
|
item_no: this.currentEditBox.item_no,
|
|
palletRemark: this.currentEditBox.palletRemark,
|
|
box_qty: this.editBoxForm.box_qty,
|
|
grossWeight: this.editBoxForm.grossWeight,
|
|
netWeight: this.editBoxForm.netWeight,
|
|
updateBy: this.$store.state.user.name
|
|
};
|
|
|
|
updateBoxInfo(updateParams).then(({ data }) => {
|
|
if (data && data.code === 0) {
|
|
this.editBoxDialogVisible = false;
|
|
this.loadBoxList()
|
|
this.$message({
|
|
message: '操作成功',
|
|
type: 'success',
|
|
duration: 1500,
|
|
onClose: () => {}
|
|
})
|
|
} else {
|
|
this.$alert(data.msg, '错误', {
|
|
confirmButtonText: '确定'
|
|
})
|
|
}
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// 提交修改明细
|
|
submitEditDetail() {
|
|
this.$refs.editDetailForm.validate(valid => {
|
|
if (valid) {
|
|
this.editDetailSubmitting = true;
|
|
|
|
// 构造更新参数
|
|
const updateParams = {
|
|
site: this.currentRow.site,
|
|
buNo: this.currentRow.buNo,
|
|
delNo: this.currentRow.delNo,
|
|
seqNo: this.currentEditDetail.seqNo,
|
|
itemNo: this.currentEditDetail.itemNo,
|
|
notifyDetailItemNo: this.currentEditDetail.notifyDetailItemNo,
|
|
poNo: this.editDetailForm.poNo,
|
|
pn: this.editDetailForm.pn,
|
|
qty: this.editDetailForm.qty,
|
|
oldQty: this.currentEditDetail.qty,
|
|
rolls: this.editDetailForm.rolls,
|
|
updateBy: this.$store.state.user.name
|
|
};
|
|
|
|
updateDetailInfo(updateParams).then(({ data }) => {
|
|
if (data && data.code === 0) {
|
|
this.editDetailDialogVisible = false;
|
|
this.loadBoxList()
|
|
this.$message({
|
|
message: '操作成功',
|
|
type: 'success',
|
|
duration: 1500,
|
|
onClose: () => {}
|
|
})
|
|
} else {
|
|
this.$alert(data.msg, '错误', {
|
|
confirmButtonText: '确定'
|
|
})
|
|
}
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// 删除明细
|
|
handleDeleteDetail(detailRow, boxRow) {
|
|
this.$confirm(`确定要删除这个明细信息吗?删除后无法恢复!`, '警告', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
// 构造删除参数
|
|
const deleteParams = {
|
|
site: this.currentRow.site,
|
|
buNo: this.currentRow.buNo,
|
|
delNo: this.currentRow.delNo,
|
|
seqNo: detailRow.seqNo,
|
|
itemNo: detailRow.itemNo,
|
|
notifyDetailItemNo: detailRow.notifyDetailItemNo,
|
|
partNo: detailRow.part_no,
|
|
qty: detailRow.qty
|
|
};
|
|
deleteDetailInfo(deleteParams).then(({data}) => {
|
|
if (data && data.code === 0) {
|
|
this.loadBoxList()
|
|
this.$message({
|
|
message: '操作成功',
|
|
type: 'success',
|
|
duration: 1500,
|
|
onClose: () => {}
|
|
})
|
|
} else {
|
|
this.$alert(data.msg, '错误', {
|
|
confirmButtonText: '确定'
|
|
})
|
|
}
|
|
})
|
|
});
|
|
},
|
|
|
|
// 计算合计行数据
|
|
getSummaries(param) {
|
|
const { columns, data } = param;
|
|
const sums = [];
|
|
|
|
columns.forEach((column, index) => {
|
|
if (index === 0) {
|
|
// 第一列(展开列)显示"合计"
|
|
sums[index] = '合计';
|
|
return;
|
|
}
|
|
|
|
const values = data.map(item => Number(item[column.property]));
|
|
|
|
// 根据列属性计算合计
|
|
if (column.property === 'box_qty') {
|
|
// 箱数合计
|
|
const sum = values.reduce((prev, curr) => {
|
|
const value = Number(curr);
|
|
if (!isNaN(value)) {
|
|
return prev + value;
|
|
} else {
|
|
return prev;
|
|
}
|
|
}, 0);
|
|
sums[index] = sum;
|
|
} else if (column.property === 'grossWeight') {
|
|
// 毛重合计
|
|
const sum = values.reduce((prev, curr) => {
|
|
const value = Number(curr);
|
|
if (!isNaN(value)) {
|
|
return prev + value;
|
|
} else {
|
|
return prev;
|
|
}
|
|
}, 0);
|
|
sums[index] = sum.toFixed(3);
|
|
} else if (column.property === 'netWeight') {
|
|
// 净重合计
|
|
const sum = values.reduce((prev, curr) => {
|
|
const value = Number(curr);
|
|
if (!isNaN(value)) {
|
|
return prev + value;
|
|
} else {
|
|
return prev;
|
|
}
|
|
}, 0);
|
|
sums[index] = sum.toFixed(3);
|
|
} else if (column.property === 'item_no') {
|
|
// 序号列显示空
|
|
sums[index] = '';
|
|
} else {
|
|
// 其他列显示空
|
|
sums[index] = '';
|
|
}
|
|
});
|
|
|
|
return sums;
|
|
},
|
|
|
|
// ========== 批量编辑相关方法 ==========
|
|
|
|
/**
|
|
* 打开批量编辑弹窗
|
|
*/
|
|
openBatchEditDialog() {
|
|
this.batchEditDialogVisible = true;
|
|
},
|
|
|
|
/**
|
|
* 加载批量编辑数据
|
|
* 将Box和明细数据扁平化为一个表格数据
|
|
*/
|
|
async loadBatchEditData() {
|
|
this.batchEditLoading = true;
|
|
this.batchEditTableData = [];
|
|
this.batchEditOriginalData = {};
|
|
this.batchEditModifiedBoxes = {};
|
|
this.batchEditModifiedDetails = {};
|
|
this.batchEditSpanInfo = [];
|
|
|
|
try {
|
|
// 先获取Box列表
|
|
const boxResponse = await selectBoxList(this.currentRow);
|
|
if (!boxResponse.data || boxResponse.data.code !== 0) {
|
|
this.$message.error('加载箱数据失败');
|
|
return;
|
|
}
|
|
|
|
const boxes = boxResponse.data.rows || [];
|
|
const tableData = [];
|
|
const spanInfo = [];
|
|
|
|
// 遍历每个Box,获取其明细
|
|
for (const box of boxes) {
|
|
const detailParams = {
|
|
site: this.currentRow.site,
|
|
buNo: this.currentRow.buNo,
|
|
delNo: this.currentRow.delNo,
|
|
seqNo: box.item_no,
|
|
palletRemark: box.palletRemark
|
|
};
|
|
|
|
const detailResponse = await searchCoDelPalletDataNew(detailParams);
|
|
const details = (detailResponse.data && detailResponse.data.code === 0)
|
|
? detailResponse.data.rows || []
|
|
: [];
|
|
|
|
// 记录该Box的起始行索引和跨行数
|
|
const startIndex = tableData.length;
|
|
const rowCount = details.length > 0 ? details.length : 1;
|
|
spanInfo.push({ startIndex, rowCount, boxKey: this.getBoxRowKey(box) });
|
|
|
|
if (details.length > 0) {
|
|
// 有明细时,为每个明细创建一行
|
|
details.forEach((detail, idx) => {
|
|
const rowData = {
|
|
// Box信息
|
|
_boxKey: this.getBoxRowKey(box),
|
|
_isFirstRowOfBox: idx === 0,
|
|
_rowSpan: idx === 0 ? details.length : 0,
|
|
item_no: box.item_no,
|
|
palletRemark: box.palletRemark,
|
|
box_qty: box.box_qty,
|
|
grossWeight: box.grossWeight,
|
|
netWeight: box.netWeight,
|
|
// 明细信息
|
|
_detailKey: `${detail.seqNo}_${detail.itemNo}_${detail.notifyDetailItemNo}`,
|
|
_hasDetail: true,
|
|
seqNo: detail.seqNo,
|
|
itemNo: detail.itemNo,
|
|
notifyDetailItemNo: detail.notifyDetailItemNo,
|
|
poNo: detail.poNo,
|
|
pn: detail.pn,
|
|
qty: detail.qty,
|
|
rolls: detail.rolls
|
|
};
|
|
tableData.push(rowData);
|
|
|
|
// 保存原始数据
|
|
this.batchEditOriginalData[rowData._detailKey] = {
|
|
qty: detail.qty,
|
|
rolls: detail.rolls
|
|
};
|
|
});
|
|
|
|
// 保存Box原始数据
|
|
this.batchEditOriginalData[this.getBoxRowKey(box)] = {
|
|
box_qty: box.box_qty,
|
|
grossWeight: box.grossWeight,
|
|
netWeight: box.netWeight
|
|
};
|
|
} else {
|
|
// 没有明细时,创建一行空明细的数据
|
|
const rowData = {
|
|
_boxKey: this.getBoxRowKey(box),
|
|
_isFirstRowOfBox: true,
|
|
_rowSpan: 1,
|
|
item_no: box.item_no,
|
|
palletRemark: box.palletRemark,
|
|
box_qty: box.box_qty,
|
|
grossWeight: box.grossWeight,
|
|
netWeight: box.netWeight,
|
|
_hasDetail: false,
|
|
poNo: '',
|
|
pn: '',
|
|
qty: '',
|
|
rolls: ''
|
|
};
|
|
tableData.push(rowData);
|
|
|
|
// 保存Box原始数据
|
|
this.batchEditOriginalData[this.getBoxRowKey(box)] = {
|
|
box_qty: box.box_qty,
|
|
grossWeight: box.grossWeight,
|
|
netWeight: box.netWeight
|
|
};
|
|
}
|
|
}
|
|
|
|
this.batchEditTableData = tableData;
|
|
this.batchEditSpanInfo = spanInfo;
|
|
} catch (error) {
|
|
console.error('加载批量编辑数据失败:', error);
|
|
this.$message.error('加载数据失败');
|
|
} finally {
|
|
this.batchEditLoading = false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 表格行合并方法
|
|
*/
|
|
batchEditSpanMethod({ row, column, rowIndex, columnIndex }) {
|
|
// Box信息列(前4列:序号、箱数、毛重、净重)需要合并
|
|
if (columnIndex < 4) {
|
|
if (row._isFirstRowOfBox) {
|
|
return {
|
|
rowspan: row._rowSpan,
|
|
colspan: 1
|
|
};
|
|
} else {
|
|
return {
|
|
rowspan: 0,
|
|
colspan: 0
|
|
};
|
|
}
|
|
}
|
|
return {
|
|
rowspan: 1,
|
|
colspan: 1
|
|
};
|
|
},
|
|
|
|
/**
|
|
* 检查Box字段是否被修改
|
|
*/
|
|
isBoxFieldModified(row, field) {
|
|
const boxKey = row._boxKey;
|
|
return this.batchEditModifiedBoxes[boxKey] &&
|
|
this.batchEditModifiedBoxes[boxKey][field] !== undefined;
|
|
},
|
|
|
|
/**
|
|
* 检查明细字段是否被修改
|
|
*/
|
|
isDetailFieldModified(row, field) {
|
|
if (!row._hasDetail) return false;
|
|
const detailKey = row._detailKey;
|
|
return this.batchEditModifiedDetails[detailKey] &&
|
|
this.batchEditModifiedDetails[detailKey][field] !== undefined;
|
|
},
|
|
|
|
/**
|
|
* 批量编辑-箱数输入时联动计算净重
|
|
* 计算公式:净重 = 毛重 - box_qty/2
|
|
*/
|
|
onBatchBoxQtyInput(row) {
|
|
if (this._isBatchCalculating) return;
|
|
this._isBatchCalculating = true;
|
|
|
|
try {
|
|
const boxQty = parseFloat(row.box_qty) || 0;
|
|
const grossWeight = parseFloat(row.grossWeight) || 0;
|
|
|
|
// 计算净重:净重 = 毛重 - box_qty/2
|
|
const netWeight = grossWeight - (boxQty / 2);
|
|
row.netWeight = netWeight.toFixed(2);
|
|
|
|
// 同步更新所有同Box的行
|
|
const boxKey = row._boxKey;
|
|
this.batchEditTableData.forEach(r => {
|
|
if (r._boxKey === boxKey) {
|
|
r.box_qty = row.box_qty;
|
|
r.netWeight = row.netWeight;
|
|
}
|
|
});
|
|
|
|
// 触发净重的变化检测
|
|
this.onBatchBoxFieldChange(row, 'netWeight');
|
|
} finally {
|
|
this._isBatchCalculating = false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 批量编辑-毛重输入时联动计算净重
|
|
* 计算公式:净重 = 毛重 - box_qty/2
|
|
*/
|
|
onBatchGrossWeightInput(row) {
|
|
if (this._isBatchCalculating) return;
|
|
this._isBatchCalculating = true;
|
|
|
|
try {
|
|
const grossWeight = parseFloat(row.grossWeight) || 0;
|
|
const boxQty = parseFloat(row.box_qty) || 0;
|
|
|
|
// 计算净重:净重 = 毛重 - box_qty/2
|
|
const netWeight = grossWeight - (boxQty / 2);
|
|
row.netWeight = netWeight.toFixed(2);
|
|
|
|
// 同步更新所有同Box的行
|
|
const boxKey = row._boxKey;
|
|
this.batchEditTableData.forEach(r => {
|
|
if (r._boxKey === boxKey) {
|
|
r.grossWeight = row.grossWeight;
|
|
r.netWeight = row.netWeight;
|
|
}
|
|
});
|
|
|
|
// 触发净重的变化检测
|
|
this.onBatchBoxFieldChange(row, 'netWeight');
|
|
} finally {
|
|
this._isBatchCalculating = false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 批量编辑-净重输入时联动计算毛重
|
|
* 计算公式:毛重 = 净重 + box_qty/2
|
|
*/
|
|
onBatchNetWeightInput(row) {
|
|
if (this._isBatchCalculating) return;
|
|
this._isBatchCalculating = true;
|
|
|
|
try {
|
|
const netWeight = parseFloat(row.netWeight) || 0;
|
|
const boxQty = parseFloat(row.box_qty) || 0;
|
|
|
|
// 计算毛重:毛重 = 净重 + box_qty/2
|
|
const grossWeight = netWeight + (boxQty / 2);
|
|
row.grossWeight = grossWeight.toFixed(2);
|
|
|
|
// 同步更新所有同Box的行
|
|
const boxKey = row._boxKey;
|
|
this.batchEditTableData.forEach(r => {
|
|
if (r._boxKey === boxKey) {
|
|
r.netWeight = row.netWeight;
|
|
r.grossWeight = row.grossWeight;
|
|
}
|
|
});
|
|
|
|
// 触发毛重的变化检测
|
|
this.onBatchBoxFieldChange(row, 'grossWeight');
|
|
} finally {
|
|
this._isBatchCalculating = false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Box字段变化处理
|
|
*/
|
|
onBatchBoxFieldChange(row, field) {
|
|
const boxKey = row._boxKey;
|
|
const original = this.batchEditOriginalData[boxKey];
|
|
|
|
if (!original) return;
|
|
|
|
// 检查是否与原始值不同
|
|
const currentValue = String(row[field]);
|
|
const originalValue = String(original[field]);
|
|
|
|
if (currentValue !== originalValue) {
|
|
// 有变化,记录修改
|
|
if (!this.batchEditModifiedBoxes[boxKey]) {
|
|
this.$set(this.batchEditModifiedBoxes, boxKey, {});
|
|
}
|
|
this.$set(this.batchEditModifiedBoxes[boxKey], field, {
|
|
oldValue: original[field],
|
|
newValue: row[field]
|
|
});
|
|
|
|
// 同步更新所有同Box的行
|
|
this.batchEditTableData.forEach(r => {
|
|
if (r._boxKey === boxKey) {
|
|
r[field] = row[field];
|
|
}
|
|
});
|
|
} else {
|
|
// 恢复原值,移除修改记录
|
|
if (this.batchEditModifiedBoxes[boxKey]) {
|
|
this.$delete(this.batchEditModifiedBoxes[boxKey], field);
|
|
if (Object.keys(this.batchEditModifiedBoxes[boxKey]).length === 0) {
|
|
this.$delete(this.batchEditModifiedBoxes, boxKey);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 明细字段变化处理
|
|
*/
|
|
onBatchDetailFieldChange(row, field) {
|
|
if (!row._hasDetail) return;
|
|
|
|
const detailKey = row._detailKey;
|
|
const original = this.batchEditOriginalData[detailKey];
|
|
|
|
if (!original) return;
|
|
|
|
const currentValue = String(row[field]);
|
|
const originalValue = String(original[field]);
|
|
|
|
if (currentValue !== originalValue) {
|
|
// 有变化,记录修改
|
|
if (!this.batchEditModifiedDetails[detailKey]) {
|
|
this.$set(this.batchEditModifiedDetails, detailKey, {
|
|
row: row // 保存行引用,方便后续提交
|
|
});
|
|
}
|
|
this.$set(this.batchEditModifiedDetails[detailKey], field, {
|
|
oldValue: original[field],
|
|
newValue: row[field]
|
|
});
|
|
} else {
|
|
// 恢复原值,移除修改记录
|
|
if (this.batchEditModifiedDetails[detailKey]) {
|
|
this.$delete(this.batchEditModifiedDetails[detailKey], field);
|
|
// 检查是否还有其他字段被修改
|
|
const remainingFields = Object.keys(this.batchEditModifiedDetails[detailKey])
|
|
.filter(k => k !== 'row');
|
|
if (remainingFields.length === 0) {
|
|
this.$delete(this.batchEditModifiedDetails, detailKey);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 获取批量编辑行样式
|
|
*/
|
|
getBatchEditRowClassName({ row, rowIndex }) {
|
|
const classes = [];
|
|
// 检查该行是否有Box修改
|
|
if (this.batchEditModifiedBoxes[row._boxKey]) {
|
|
classes.push('box-modified-row');
|
|
}
|
|
// 检查该行是否有明细修改
|
|
if (row._hasDetail && this.batchEditModifiedDetails[row._detailKey]) {
|
|
classes.push('detail-modified-row');
|
|
}
|
|
return classes.join(' ');
|
|
},
|
|
|
|
/**
|
|
* 保存批量编辑
|
|
*/
|
|
async saveBatchEdit() {
|
|
if (this.batchEditModifiedCount === 0) {
|
|
this.$message.warning('没有需要保存的修改');
|
|
return;
|
|
}
|
|
|
|
this.batchEditSaving = true;
|
|
|
|
try {
|
|
// 构造Box修改列表
|
|
const boxList = [];
|
|
for (const boxKey of Object.keys(this.batchEditModifiedBoxes)) {
|
|
const row = this.batchEditTableData.find(r => r._boxKey === boxKey);
|
|
if (!row) continue;
|
|
|
|
boxList.push({
|
|
item_no: row.item_no,
|
|
palletRemark: row.palletRemark,
|
|
box_qty: row.box_qty,
|
|
grossWeight: row.grossWeight,
|
|
netWeight: row.netWeight
|
|
});
|
|
}
|
|
|
|
// 构造明细修改列表
|
|
const detailList = [];
|
|
for (const detailKey of Object.keys(this.batchEditModifiedDetails)) {
|
|
const detailMod = this.batchEditModifiedDetails[detailKey];
|
|
const row = detailMod.row;
|
|
if (!row) continue;
|
|
|
|
detailList.push({
|
|
seqNo: row.seqNo,
|
|
itemNo: row.itemNo,
|
|
notifyDetailItemNo: row.notifyDetailItemNo,
|
|
poNo: row.poNo,
|
|
pn: row.pn,
|
|
qty: row.qty,
|
|
rolls: row.rolls
|
|
});
|
|
}
|
|
|
|
// 调用批量修改API
|
|
const batchParams = {
|
|
site: this.currentRow.site,
|
|
buNo: this.currentRow.buNo,
|
|
delNo: this.currentRow.delNo,
|
|
updateBy: this.$store.state.user.name,
|
|
boxList: boxList,
|
|
detailList: detailList
|
|
};
|
|
|
|
const response = await batchUpdatePackingInfo(batchParams);
|
|
|
|
if (response.data && response.data.code === 0) {
|
|
this.$message.success(`成功保存 ${this.batchEditModifiedCount} 处修改`);
|
|
this.batchEditDialogVisible = false;
|
|
this.loadBoxList(); // 刷新主表格
|
|
} else {
|
|
this.$alert(response.data.msg || '保存失败', '错误', {
|
|
confirmButtonText: '确定'
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('批量保存失败:', error);
|
|
this.$message.error('保存失败');
|
|
} finally {
|
|
this.batchEditSaving = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.packing-detail-tab {
|
|
width: 100%;
|
|
}
|
|
|
|
/* 展开明细容器样式 */
|
|
.expand-detail-container {
|
|
background: #fafafa;
|
|
border-radius: 6px;
|
|
overflow: visible;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
/* 加载状态样式 */
|
|
.expand-loading {
|
|
text-align: center;
|
|
padding: 30px;
|
|
color: #666;
|
|
background: #fafafa;
|
|
margin: 8px 16px;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.expand-loading i {
|
|
font-size: 18px;
|
|
margin-right: 8px;
|
|
color: #409eff;
|
|
}
|
|
|
|
/* 明细表格样式 */
|
|
.expand-detail-table {
|
|
margin: 0;
|
|
border: none;
|
|
}
|
|
|
|
/deep/ .expand-detail-table .el-table__body-wrapper {
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/deep/ .expand-detail-table .el-table__header {
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
/deep/ .expand-detail-table .el-table__header th {
|
|
background: #eef7f0;
|
|
color: #333;
|
|
font-weight: 500;
|
|
border-bottom: 2px solid #e9ecef;
|
|
}
|
|
|
|
/deep/ .expand-detail-table .el-table__row:hover > td {
|
|
background-color: #f0f9ff;
|
|
}
|
|
|
|
/deep/ .expand-detail-table .el-table__row.el-table__row--striped {
|
|
background: #fbfcfd;
|
|
}
|
|
|
|
/deep/ .expand-detail-table .el-table__row.el-table__row--striped:hover > td {
|
|
background-color: #f0f9ff;
|
|
}
|
|
|
|
/* 空数据状态样式 */
|
|
.expand-empty-state {
|
|
text-align: center;
|
|
padding: 40px 20px;
|
|
color: #999;
|
|
}
|
|
|
|
.expand-empty-state i {
|
|
font-size: 48px;
|
|
color: #ddd;
|
|
margin-bottom: 12px;
|
|
display: block;
|
|
}
|
|
|
|
.expand-empty-state p {
|
|
font-size: 16px;
|
|
margin: 0 0 8px 0;
|
|
color: #666;
|
|
}
|
|
|
|
.expand-empty-state span {
|
|
font-size: 13px;
|
|
color: #999;
|
|
}
|
|
|
|
/* 响应式调整 */
|
|
@media (max-width: 768px) {
|
|
.expand-detail-container {
|
|
margin: 8px 8px;
|
|
padding: 6px;
|
|
}
|
|
}
|
|
|
|
/* 确保主表格容器的滚动行为 */
|
|
/deep/ .el-table__expanded-cell {
|
|
padding: 0 !important;
|
|
}
|
|
|
|
/deep/ .el-table__expand-column .cell {
|
|
padding: 0;
|
|
}
|
|
|
|
/* 确保表格滚动条正常显示 */
|
|
/deep/ .el-table .el-table__body-wrapper {
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/deep/ .el-table__body-wrapper::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
/deep/ .el-table__body-wrapper::-webkit-scrollbar-track {
|
|
background: #f1f1f1;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
/deep/ .el-table__body-wrapper::-webkit-scrollbar-thumb {
|
|
background: #c1c1c1;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
/deep/ .el-table__body-wrapper::-webkit-scrollbar-thumb:hover {
|
|
background: #a8a8a8;
|
|
}
|
|
|
|
/* 批量编辑工具栏 */
|
|
.batch-edit-toolbar {
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
/* 批量编辑弹窗样式 */
|
|
/deep/ .batch-edit-dialog {
|
|
border-radius: 8px;
|
|
}
|
|
|
|
/deep/ .batch-edit-dialog .el-dialog__header {
|
|
background-color: #f5f7fa;
|
|
border-bottom: 1px solid #e4e7ed;
|
|
padding: 15px 20px;
|
|
border-radius: 8px 8px 0 0;
|
|
}
|
|
|
|
/deep/ .batch-edit-dialog .el-dialog__title {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: #303133;
|
|
}
|
|
|
|
/deep/ .batch-edit-dialog .el-dialog__body {
|
|
padding: 15px 20px;
|
|
}
|
|
|
|
/deep/ .batch-edit-dialog .el-dialog__footer {
|
|
border-top: 1px solid #e4e7ed;
|
|
padding: 12px 20px;
|
|
}
|
|
|
|
/* 批量编辑弹窗容器 */
|
|
.batch-edit-container {
|
|
min-height: 300px;
|
|
}
|
|
|
|
/* 批量编辑提示 */
|
|
.batch-edit-tips {
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.batch-edit-tips .modified-count {
|
|
color: #e6a23c;
|
|
margin-left: 10px;
|
|
}
|
|
|
|
.batch-edit-tips .modified-count b {
|
|
color: #f56c6c;
|
|
font-size: 16px;
|
|
}
|
|
|
|
/* 批量编辑表格样式 */
|
|
/deep/ .batch-edit-container .el-table {
|
|
border-radius: 4px;
|
|
border: 1px solid #ebeef5;
|
|
}
|
|
|
|
/* 表头样式 - 确保表头可见 */
|
|
/deep/ .batch-edit-container .el-table__header-wrapper {
|
|
background-color: #f5f7fa;
|
|
}
|
|
|
|
/deep/ .batch-edit-container .el-table th {
|
|
background-color: #f5f7fa !important;
|
|
color: #606266 !important;
|
|
font-weight: 600;
|
|
font-size: 13px;
|
|
padding: 8px 0;
|
|
}
|
|
|
|
/deep/ .batch-edit-container .el-table th .cell {
|
|
color: #606266 !important;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Box信息单元格样式 */
|
|
.box-info-cell {
|
|
font-weight: 600;
|
|
color: #409eff;
|
|
font-size: 13px;
|
|
}
|
|
|
|
/* 修改过的输入框样式 */
|
|
/deep/ .batch-edit-container .modified-input .el-input__inner {
|
|
background-color: #fff7e6;
|
|
border-color: #e6a23c;
|
|
color: #e6a23c;
|
|
}
|
|
|
|
/* 修改过的行样式 */
|
|
/deep/ .batch-edit-container .box-modified-row td:nth-child(-n+4) {
|
|
background-color: #fdf6ec !important;
|
|
}
|
|
|
|
/deep/ .batch-edit-container .detail-modified-row td:nth-child(n+5) {
|
|
background-color: #fff7e6 !important;
|
|
}
|
|
|
|
/* 输入框样式 */
|
|
/deep/ .batch-edit-container .el-input--mini .el-input__inner {
|
|
text-align: center;
|
|
padding: 0 8px;
|
|
border-color: #dcdfe6;
|
|
}
|
|
|
|
/deep/ .batch-edit-container .el-input--mini .el-input__inner:focus {
|
|
border-color: #409eff;
|
|
}
|
|
|
|
/* 表格单元格内边距 */
|
|
/deep/ .batch-edit-container .el-table td {
|
|
padding: 6px 0;
|
|
}
|
|
|
|
/deep/ .batch-edit-container .el-table .cell {
|
|
padding: 0 8px;
|
|
}
|
|
|
|
/* 数字输入框隐藏上下箭头 */
|
|
/deep/ .batch-edit-container input[type="number"]::-webkit-inner-spin-button,
|
|
/deep/ .batch-edit-container input[type="number"]::-webkit-outer-spin-button {
|
|
-webkit-appearance: none;
|
|
margin: 0;
|
|
}
|
|
|
|
/deep/ .batch-edit-container input[type="number"] {
|
|
-moz-appearance: textfield;
|
|
}
|
|
|
|
/* 合并单元格的垂直居中 */
|
|
/deep/ .batch-edit-container .el-table__body td[rowspan] {
|
|
vertical-align: middle;
|
|
}
|
|
|
|
/deep/ .batch-edit-container .el-table__body td[rowspan] .cell {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100%;
|
|
}
|
|
|
|
/* 文字样式 */
|
|
/deep/ .batch-edit-container .el-table .cell span {
|
|
font-size: 13px;
|
|
color: #606266;
|
|
}
|
|
</style>
|