|
|
<template> <div class="mod-config"> <el-form :inline="true" label-position="top" label-width="100px" style="margin-top: 0px;"> <el-form-item :label="'BU:'"> <el-select v-model="searchData.buNo" placeholder="请选择" > <el-option label="全部" value=""></el-option> <el-option v-for = "i in buList" :key = "i.buNo" :label = "i.buDesc" :value = "i.buNo"> </el-option> </el-select> </el-form-item> <el-form-item :label="'发货通知单:'"> <el-input v-model="searchData.delNo" style="width: 120px"></el-input> </el-form-item> <el-form-item :label="'CMC Invoice:'"> <el-input v-model="searchData.cmcInvoice" style="width: 120px"></el-input> </el-form-item> <el-form-item :label="'通知单状态:'"> <el-select filterable v-model="searchData.notifyStatus" style="width: 120px"> <el-option label="全部" value=""></el-option> <el-option label="已下达" value="已下达"></el-option> <el-option label="仓库已确认" value="仓库已确认"></el-option> <el-option label="已报关" value="已报关"></el-option> <el-option label="订单取消" value="订单取消"></el-option> </el-select> </el-form-item> <el-form-item :label="'ReadyDate'" > <el-date-picker style="width: 120px" v-model="searchData.startDate" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd" placeholder="选择日期"> </el-date-picker> </el-form-item> <el-form-item :label="'To'" > <el-date-picker style="width: 120px" v-model="searchData.endDate" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd" placeholder="选择日期"> </el-date-picker> </el-form-item> <el-form-item :label="'是否导出:'"> <el-select v-model="searchData.exportFlag" style="width: 120px"> <el-option label="全部" value=""></el-option> <el-option label="已导出" value="Y"></el-option> <el-option label="未导出" value="N"></el-option> </el-select> </el-form-item> <el-form-item label="改单"> <el-checkbox v-model="searchData.modifyData" true-label="true" false-label="false" @change="searchTable()"></el-checkbox> </el-form-item> <el-form-item :label="' '" > <el-button @click="searchTable()" type="primary" style="margin-left: 2px;margin-top: 0px">{{'查询'}}</el-button> </el-form-item> </el-form>
<el-table @row-click="changeData" highlight-current-row :height="height" :data="dataList" ref="mainTable" border :cell-style="cellStyle" :row-class-name="tableRowClassName" v-loading="dataListLoading" style="width: 100%;"> <el-table-column header-align="center" align="center" width="100" fixed="left" label="操作"> <template slot-scope="scope"> <a type="text" size="small" v-if="scope.row.notifyStatus==='已报关'" @click="updateModelOpen(scope.row)">修改</a> <a type="text" size="small" v-if="scope.row.notifyStatus==='已下达'" @click="confirmModelOpen(scope.row)">仓库确认</a> <a type="text" size="small" v-if="scope.row.notifyStatus==='仓库已确认'" @click="cancerConfirm(scope.row)">取消确认</a> </template> </el-table-column> <el-table-column v-for="(item,index) in columnList1" :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> <el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[20, 50, 100, 1000]" :page-size="pageSize" :total="totalPage" layout="total, sizes, prev, pager, next, jumper"> </el-pagination> <el-tabs style="font-size: 12px;min-height: 200px" class="customer-tab" v-model="activeName" type="border-card" @tab-click="tabClick" > <el-tab-pane :label="currentRow.cmcInvoice+'明细'" name="detail"> <el-table :height="height" ref="cloDetailTable" :data="dataList2" show-summary :summary-method="getDetailSummaries" border :cell-style="cellStyleDetail" style="width: 100%;"> <el-table-column v-for="(item,index) in columnList2" :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.columnProp === 'ttlAmount' || item.columnProp === 'sumPrice'"> {{!!scope.row[item.columnProp]?scope.row[item.columnProp].toFixed(2):''}} </span>
<!-- PN字段特殊处理,添加提示信息 --> <template v-else-if="item.columnProp === 'pn'"> <el-tooltip v-if="isPnDataIncomplete(scope.row)" :content="getPnIncompleteTooltip(scope.row)" placement="top"> <span v-if="!item.columnHidden" class="clickable-pn" @click="navigateToPartHsCode(scope.row.pn)"> {{ scope.row[item.columnProp] }} </span> </el-tooltip> <span v-else-if="!item.columnHidden">{{ scope.row[item.columnProp] }}</span> </template>
<!-- 其他字段正常处理 --> <template v-else> <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> </template> </el-table-column>
</el-table> </el-tab-pane>
<el-tab-pane label="手工装箱" name="box"><!-- <el-button @click="oneClickPacking()" type="primary" style="margin-left: 2px;margin-top: 0px">{{'一键装箱'}}</el-button> <el-button @click="newPalletModel()" type="primary" style="margin-left: 2px;margin-top: 0px">{{'装箱'}}</el-button>--> <el-button @click="openMergeBoxDialog()" type="primary" style="margin-left: 2px;margin-top: 0px">{{'装箱'}}</el-button> <el-button @click="palletMaintenance()" type="primary" style="margin-left: 2px;margin-top: 0px">{{'栈板维护'}}</el-button> <el-button @click="exportExcel()" type="primary" style="margin-left: 2px;margin-top: 0px">{{'导出装箱数据'}}</el-button> <el-button @click="upLoadPallet()" type="success" style="margin-left: 2px;margin-top: 0px">{{'导入装箱单'}}</el-button> <el-table ref="detailTable" :data="dataList4" :height="height" border show-summary :summary-method="getSummaries" v-loading="dataListLoading" style="width: 100%; "> <el-table-column header-align="center" align="center" width="150" fixed="left" label="操作"> <template slot-scope="scope"> <a type="text" size="small" @click="updatePalletModel(scope.row)">修改</a> <a type="text" size="small" @click="deletePallet(scope.row)">删除</a> </template> </el-table-column> <el-table-column v-for="(item,index) in columnList4" :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> </el-tab-pane>
<el-tab-pane label="装箱明细" name="pallet"> <packing-detail-tab ref="packingDetailTab" :current-row="currentRow" :height="height" :show-actions="true" @refresh="searchTable"> </packing-detail-tab> </el-tab-pane> <el-tab-pane label="相关文档" name="codelnotifyConfirmDocument"> <oss-components label="申请单号" style="margin-top: 5px" height="44vh" :columns="ossColumns" :order-ref1="currentRow.site" :order-ref2="currentRow.delNo" :codelnotifyFlag="'2'" :rfq-no="currentRow.delNo"> </oss-components> </el-tab-pane> </el-tabs>
<el-dialog title="仓库确认" :close-on-click-modal="false" v-drag :visible.sync="confirmModelFlag" width="400px"> <el-form label-position="top" style="margin-left: 7px;margin-top: -5px;"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item :label="'CMC Invoice'" > <el-input v-model="confirmModel.cmcInvoice" disabled ></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item :label="'ReadyDate'" > <el-input v-model="confirmModel.readyDate" disabled ></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item :label="'预计发货日期'" > <el-date-picker style="width: 100%" v-model="confirmModel.notifyDate" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd" placeholder="选择日期"> </el-date-picker> </el-form-item> </el-col> </el-row> </el-form> <el-footer style="height:40px;margin-top: 10px;text-align:center"> <el-button type="primary" @click="confirmDo()">保存</el-button> <el-button type="primary" @click="confirmModelFlag=false">关闭</el-button> </el-footer> </el-dialog>
<el-dialog title="修改" :close-on-click-modal="false" v-drag :visible.sync="updateModelFlag" width="350px"> <el-form label-position="top" style="margin-left: 7px;margin-top: -5px;"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item :label="'ReadyDate'" > <el-date-picker style="width: 100%" v-model="confirmModel.readyDate" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd" placeholder="选择日期"> </el-date-picker> </el-form-item> </el-col> <el-col :span="12"> <el-form-item :label="'预计发货日期'" > <el-date-picker style="width: 100%" v-model="confirmModel.notifyDate" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd" placeholder="选择日期"> </el-date-picker> </el-form-item> </el-col> </el-row> </el-form> <el-footer style="height:40px;margin-top: 10px;text-align:center"> <el-button type="primary" @click="updateDo()">保存</el-button> <el-button type="primary" @click="updateModelFlag=false">关闭</el-button> </el-footer> </el-dialog>
<el-dialog title="维护箱" :close-on-click-modal="false" v-drag :visible.sync="boxModelFlag" width="500px"> <el-form label-position="top" style="margin-left: 7px;margin-top: -5px;"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item :label="boxModelData.type===1?'物料编码':''"> <span v-if="boxModelData.type===0" slot="label" @click="openPartDialog()"><a herf="#">物料编码</a></span> <el-input v-model="boxModelData.pn" :disabled="boxModelData.type===1" ></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item :label="'数量'" > <el-input v-model="boxModelData.qty" type="number" ></el-input> </el-form-item> </el-col> <el-col :span="12" v-if="boxModelData.type===0"> <el-form-item :label="'PO'" > <el-input v-model="boxModelData.poNo" ></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item :label="'箱数'" > <el-input v-model="boxModelData.boxQty"></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item :label="'ROLLS'" > <el-input v-model="boxModelData.rolls" ></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item :label="'毛重'" > <el-input v-model="boxModelData.grossWeight"></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item :label="'净重'" > <el-input v-model="boxModelData.netWeight" ></el-input> </el-form-item> </el-col> </el-row> </el-form> <el-footer style="height:40px;margin-top: 10px;text-align:center"> <el-button type="primary" @click="saveBoxHeader()">保存</el-button> <el-button type="primary" @click="boxModelFlag=false">关闭</el-button> </el-footer> </el-dialog>
<!-- 装箱(新增/修改栈板) --> <el-dialog :title="palletModelData.addFlag===1 ? '修改栈板' : '手工装箱'" :close-on-click-modal="false" v-drag :visible.sync="palletModelFlag" width="780px" class="pallet-dialog">
<!-- 区域 1:箱信息 --> <div class="section section-header"> <h4 class="section-title">箱信息</h4> <el-divider></el-divider> <el-form label-position="top" class="box-info-form"> <el-row :gutter="20"> <el-col :span="6"> <el-form-item label="箱数"> <el-input v-model="palletModelData.boxQty" type="number" placeholder="请输入箱数" @input="calculateWeightsByBoxQty"></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="毛重"> <el-input v-model="palletModelData.grossWeight" type="number" placeholder="自动计算" @input="onPalletGrossWeightChange"></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="净重"> <el-input v-model="palletModelData.netWeight" type="number" placeholder="自动计算" @input="onPalletNetWeightChange"></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="总Rolls(箱明细无rolls才可修改)"> <el-input v-model="palletModelData.rolls" type="number" placeholder="箱明细无rolls才可修改" :disabled="isTotalRollsDisabled" ></el-input> </el-form-item> </el-col> </el-row> </el-form> </div>
<!-- 区域 2:箱明细 --> <div class="section section-detail"> <h4 class="section-title">箱明细</h4> <el-divider></el-divider> <div class="table-wrapper"> <el-table ref="partTableRef" :data="dataList8" height="100%" stripe border class="zxClass" style="width: 100%;"> <el-table-column prop="pn" label="PN" min-width="120"></el-table-column> <el-table-column prop="partDescription" label="Description" min-width="220"></el-table-column> <el-table-column prop="qty" label="原数量" align="right" width="70"></el-table-column> <el-table-column prop="surplusQty" label="可装箱数量" align="right" width="80"></el-table-column> <el-table-column label="装箱数量" align="center" width="80"> <template slot-scope="scope"> <el-input v-model.number="scope.row.useQty" type="number" :min="0" :max="999999" size="mini" @input="calculateRolls(scope.row)"></el-input> </template> </el-table-column> <el-table-column label="Rolls" align="center" width="80"> <template slot-scope="scope"> <el-input v-model="scope.row.rolls" type="number" :min="0" :max="999999" size="mini" placeholder="自动计算" @input="delayCalculateTotalRolls"></el-input> </template> </el-table-column> <el-table-column label="操作" align="center" width="70"> <template slot-scope="scope"> <a type="text" size="small" @click="fillUseQty(scope.row)">全数装箱</a> </template> </el-table-column> </el-table> </div> </div>
<!-- 底部操作按钮 --> <div slot="footer" class="dialog-footer"> <el-button type="primary" @click="savePalletHeader(0)">保存</el-button> <el-button type="primary" @click="savePalletHeader(1)">保存并关闭</el-button> <el-button @click="palletModelFlag=false">关闭</el-button> </div> </el-dialog>
<el-dialog :title=" '修改栈板'" :close-on-click-modal="false" v-drag :visible.sync="palletEditFlag" width="240px" class="pallet-dialog"> <div class="section section-header"> <el-divider></el-divider> <el-form label-position="top" class="box-info-form"> <el-row :gutter="20"> <el-col :span="24"> <el-form-item label="栈板高度(M)"> <el-input v-model="palletModelData.height" type="number" placeholder="请输入栈板高度(M)"></el-input> </el-form-item> </el-col> <el-col :span="24"> <el-form-item label="托数"> <el-input v-model="palletModelData.palletQty" type="number" placeholder="请输入托数"></el-input> </el-form-item> </el-col> </el-row> </el-form> </div> <!-- 底部操作按钮 --> <div slot="footer" class="dialog-footer"> <el-button type="primary" @click="updateCodelPalletHeaderPalletQty">保存</el-button> <el-button @click="palletEditFlag=false">关闭</el-button> </div> </el-dialog>
<el-dialog title="一键装箱" :close-on-click-modal="false" v-drag :visible.sync="oneClickPackingModelFlag" width="170px"> <el-form label-position="top" style="margin-left: 7px;margin-top: 10px;"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item :label="''" > <el-checkbox v-model="oneClickPackingModelData.boxRemnant">是否显示零数箱</el-checkbox> </el-form-item> </el-col> </el-row> </el-form> <el-footer style="height:40px;margin-top: 10px;text-align:center"> <el-button type="primary" @click="saveOneClickPacking()">保存</el-button> <el-button type="primary" @click="oneClickPackingModelFlag=false">关闭</el-button> </el-footer> </el-dialog>
<!-- 合箱批量编辑弹出框 --> <el-dialog title="合箱批量编辑" :visible.sync="mergeBoxDialogVisible" width="60%" top="5vh" custom-class="batch-edit-dialog" :close-on-click-modal="false" @open="loadMergeBoxData"> <div class="batch-edit-container" v-loading="mergeBoxLoading"> <!-- 操作工具栏 --> <div class="merge-box-toolbar"> <el-button type="primary" size="small" icon="el-icon-connection" :disabled="mergeBoxSelection.length < 2" @click="doMergeBoxes"> 合并选中的箱 ({{ mergeBoxSelection.length }}) </el-button> <el-button type="warning" size="small" icon="el-icon-refresh-left" :disabled="mergeBoxSelection.length === 0" @click="doUnmergeSelectedBoxes"> 取消合并 </el-button> <div class="merge-stats"> <el-tag type="success" size="small">总箱数: {{ getUniqueBoxCount() }}</el-tag> <span v-if="mergeBoxModifiedCount > 0" class="modified-count"> 已修改 <b>{{ mergeBoxModifiedCount }}</b> 处 </span> </div> </div>
<!-- 操作提示 --> <div class="batch-edit-tips"> <el-alert type="info" :closable="false" show-icon> <template slot="title"> <span>直接在表格中编辑数据,选择多个箱点击"合并"按钮可以合箱,选择已合并的箱点击"取消合并"可以拆分,修改后点击"保存所有修改"按钮提交</span> </template> </el-alert> </div>
<!-- 行合并表格 --> <el-table ref="mergeBoxTable" :data="mergeBoxTableData" :span-method="mergeBoxSpanMethod" border class="zxClass" size="small" height="50vh" style="width: 100%" @selection-change="handleMergeBoxSelectionChange" :row-class-name="getMergeBoxRowClassName" :header-cell-style="{background:'#f5f7fa', color:'#606266', fontWeight:'600'}">
<!-- 复选框列 - 只在第一行显示 --> <el-table-column type="selection" width="55" align="center" :selectable="row => row._isFirstRowOfBox"> </el-table-column>
<!-- 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="onMergeBoxQtyInput(scope.row)" @change="onMergeBoxFieldChange(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="onMergeGrossWeightInput(scope.row)" @change="onMergeBoxFieldChange(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="onMergeNetWeightInput(scope.row)" @change="onMergeBoxFieldChange(scope.row, 'netWeight')"> </el-input> </template> </el-table-column>
<el-table-column label="总Rolls" prop="rolls" width="100" align="center"> <template slot-scope="scope"> <el-input v-model="scope.row.rolls" size="mini" type="number" :disabled="hasDetailRolls(scope.row)" :placeholder="hasDetailRolls(scope.row) ? '自动计算' : '请输入'" :class="{'modified-input': isBoxFieldModified(scope.row, 'rolls')}" @change="onMergeBoxFieldChange(scope.row, 'rolls')"> </el-input> </template> </el-table-column>
<!-- 明细信息列(不合并) --> <el-table-column label="PO" prop="poNo" min-width="120" align="center"> <template slot-scope="scope"> <span>{{ scope.row.poNo || '-' }}</span> </template> </el-table-column>
<el-table-column label="PN" prop="pn" min-width="120" align="center"> <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')}" @input="onDetailQtyChange(scope.row)" @change="onMergeDetailFieldChange(scope.row, 'qty')"> </el-input> </template> </el-table-column>
<el-table-column label="Rolls" prop="detailRolls" width="80" align="center"> <template slot-scope="scope"> <el-input v-model="scope.row.detailRolls" size="mini" type="number" :class="{'modified-input': isDetailFieldModified(scope.row, 'detailRolls')}" @input="onDetailRollsInput(scope.row)" @change="onMergeDetailFieldChange(scope.row, 'detailRolls')"> </el-input> </template> </el-table-column> </el-table> </div>
<div slot="footer" class="dialog-footer"> <el-button @click="mergeBoxDialogVisible = false">取消</el-button> <el-button type="primary" :loading="mergeBoxSaving" :disabled="getUniqueBoxCount() === 0" @click="saveMergeBoxEdit"> 保存所有修改 ({{ getUniqueBoxCount() }}箱 / {{ mergeBoxModifiedCount }}处修改) </el-button> </div> </el-dialog>
<el-dialog :close-on-click-modal="false" v-drag :visible.sync="palletMaintenanceModelFlag" width="450px"> <div slot="title" class="dialog-title"> <span>栈板维护</span> <el-tooltip effect="dark" placement="top"> <div slot="content"> <div>栈板维护功能说明:</div> <div>• 系统会自动加载当前BU下的所有栈板</div> <div>• 栈板高度单位为米(M),请输入准确数值</div> <div>• 只有托数大于0的栈板记录才会被保存</div> </div> <i class="el-icon-question" style="color: #17b3a3; margin-left: 8px; cursor: pointer; font-size: 16px;"></i> </el-tooltip> </div> <!-- 栈板记录列表 --> <div style="margin: 15px 0;"> <el-table :data="palletMaintenanceRecords" border style="width: 100%; margin-bottom: 15px;" class="zxClass" max-height="200" v-if="palletMaintenanceRecords.length > 0"> <el-table-column label="栈板类型" min-width="100"> <template slot-scope="scope"> <el-input v-model="scope.row.palletType" disabled style="width: 100%;"></el-input> </template> </el-table-column> <el-table-column width="120"> <template slot="header"> <span>栈板高度(M)</span> </template> <template slot-scope="scope"> <el-input v-model="scope.row.height" type="text" placeholder="请输入高度" style="width: 100%;"></el-input> </template> </el-table-column> <el-table-column width="100"> <template slot="header"> <span>托数</span> </template> <template slot-scope="scope"> <el-input v-model="scope.row.palletQty" type="text" placeholder="请输入托数" style="width: 100%;"></el-input> </template> </el-table-column> </el-table> <div v-if="palletMaintenanceRecords.length === 0" style="text-align: center; color: #999; padding: 20px; border: 1px dashed #ddd;"> 正在加载栈板记录... </div>
<!-- 操作提示 --> <div v-if="palletMaintenanceRecords.length > 0" style="margin-top: 10px; padding: 8px 12px; background: #f0f9ff; border: 1px solid #b3d8ff; border-radius: 4px; font-size: 12px; color: #409EFF;"> <i class="el-icon-info" style="margin-right: 4px;"></i> <span>提示:托数大于0的记录才会被保存。</span> </div> </div> <el-footer style="height:40px;margin-top: 10px;text-align:center"> <el-button type="primary" :loading="saveLoading" :disabled="saveLoading" @click="savePalletMaintenance()">确定</el-button> <el-button type="primary" @click="palletMaintenanceModelFlag=false">关闭</el-button> </el-footer> </el-dialog> <el-dialog title="物料信息" @close="closePartDialog" @open="openPartDialog" :visible.sync="partFlag" width="559px" v-drag> <el-form inline="inline" label-position="top" :model="partData" style="margin-left: 7px;margin-top: -5px;">
</el-form> <el-table :height="height + 110" :data="partList" stripe highlight-current-row border @row-dblclick="partRowDblclick" style="width: 100%;"> <el-table-column prop="pn" header-align="center" align="center" label="物料编码"> </el-table-column> <el-table-column prop="part_desc" header-align="center" align="center" label="物料名称"> </el-table-column> </el-table> <el-footer style="height:40px;margin-top: 10px;text-align:center"> <el-button @click="partFlag = false">关闭</el-button> </el-footer> </el-dialog>
<el-dialog title="栈板" @close="closePalletDialog" @open="openPalletDialog" :visible.sync="palletFlag" width="559px" v-drag> <el-form inline="inline" label-position="top" :model="palletData" style="margin-left: 7px;margin-top: -5px;"> <el-form-item label="栈板类型"> <el-input v-model="palletData.palletType" clearable style="width: 110px"></el-input> </el-form-item> <el-form-item label=" "> <el-button type="primary" style="padding: 3px 12px" @click="searchPalletList()">查询</el-button> </el-form-item> </el-form> <el-table :height="height + 110" :data="palletList" stripe highlight-current-row border @row-dblclick="palletRowDblclick" style="width: 100%;"> <el-table-column prop="palletNo" header-align="center" align="center" width="120" label="栈板编码"> </el-table-column> <el-table-column prop="palletType" header-align="center" align="center" label="栈板类型"> </el-table-column> <el-table-column prop="applicationArea" header-align="center" align="center" label="应用环境"> </el-table-column> <el-table-column prop="length" header-align="center" align="center" label="长(M)"> </el-table-column> <el-table-column prop="width" header-align="center" align="center" label="宽(M)"> </el-table-column> <el-table-column prop="height" header-align="center" align="center" label="栈板高(M)"> </el-table-column> </el-table> <el-footer style="height:40px;margin-top: 10px;text-align:center"> <el-button @click="palletFlag = false">关闭</el-button> </el-footer> </el-dialog> <!-- 导入 --> <pallet-upload-excel ref="palletUploadExcel" @refreshTable="searchPalletTable" v-drag></pallet-upload-excel> <!--列表的组件--> <Chooselist ref="baseList" @getBaseData="getBaseData"></Chooselist> </div></template>
<script> import Chooselist from '@/views/modules/common/Chooselist_eam' import {} from "@/api/sysLanguage.js" import palletUploadExcel from "./pallet_upload_excel.vue"; import PackingDetailTab from "./components/PackingDetailTab.vue"; import OssComponents from '../oss/ossComponents.vue' import { searchEcssCoDelNotifyHeaderForCK, searchEcssCoDelNotifyDetail, confirmEcssDel, updateEcssDel, cancerConfirmEcssDel, searchCoDelPalletDataNew, selectBoxList, searchEcssCoDelPalletHeaderData, searchEcssCoDelPalletDetailData, savePalletHeader, deletePalletHeader, savePalletDetail, deletePalletDetail, saveOneClickPacking, savePalletMaintenance, getNotifyPartDetail, searchPalletList, updateExportFlag, updateCodelPalletHeaderPalletQty, getPartPackageProperties, mergeBox }from "@/api/ecss/ecss.js" import {getBuList}from '@/api/factory/site.js' import excel from "@/utils/excel-util.js"; import excelOpts from '@/utils/export-options.js' import ExportUtil from "@/utils/export"; import { getTableUserListLanguage} from "@/api/table.js" import {getTableDefaultListLanguage} from "../../../api/table"; export default { name: "null", components:{ OssComponents, palletUploadExcel, Chooselist, PackingDetailTab, }, data() { return { multipleSelection: [], palletFlag:false, palletList:[], palletData:{}, partFlag:false, partData:{}, partList:[],
pageIndex: 1, pageSize: 100, totalPage: 0, // 选中行持久化相关
selectedRowKey: null, // 当前选中行的唯一标识
height: 200, buList:[], dataList:[], dataList2:[], dataList3:[], dataList4:[], dataList5:[], dataList8:[], notifyDetailMap: new Map(), boxDetailData:{ site:'', buNo:'', delNo:'', seqNo:'', }, dataListLoading: false, boxDetailModelFlag: false, searchData: { page: 1, limit: 100, buNo:'', delNo:'', cmcInvoice:'', notifyStatus:'', startDate:'', endDate:'', exportFlag:'', username:this.$store.state.user.name, }, oneClickPackingModelFlag:false, oneClickPackingModelData:{ boxRemnant: false, },
// 合箱批量编辑相关
mergeBoxDialogVisible: false, mergeBoxLoading: false, mergeBoxSaving: false, mergeBoxTableData: [], // 扁平化的表格数据
mergeBoxSelection: [], // 已选择的箱(用于合箱)
mergeBoxOriginalData: {}, // 原始数据快照(用于对比是否修改)
mergeBoxModifiedBoxes: {}, // 修改过的Box记录
mergeBoxMergeHistory: [], // 合并历史记录(用于取消合并)
mergeBoxModifiedDetails: {}, // 修改过的明细记录
nextItemNo: 1, // 下一个序号
// 栈板维护相关
palletMaintenanceModelFlag: false, saveLoading: false, palletMaintenanceRecords: [], palletModelFlag:false, palletEditFlag:false, palletModelData:{ addFlag:0, site:'', buNo:'', delNo:'', seqNo:'', palletNo:'', palletQty:'', length:'', width:'', height:'', boxQty:'', grossWeight:'', netWeight:'', palletRemark:'', rolls:'',
}, boxModelFlag:false, boxModelData:{ addFlag:0, site:'', buNo:'', delNo:'', seqNo:'', itemNo:'', partNo:'', pn:'', qty:'', poNo:'', boxQty:'', rolls:'',
}, buttons:{ search:'查询', }, confirmModelFlag:false, updateModelFlag:false, confirmModel:{ site:'', buDesc:'', cmcInvoice:'', delNo:'', readyDate:'', shippingMode:'', destination:'', notifyDate:'', remark:'', },
activeName:'detail', columnList1: [ { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1BuDesc', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "buDesc", headerAlign: "center", align: "left", columnLabel: "BU", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 60 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1CmcInvoice', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "cmcInvoice", headerAlign: "center", align: "left", columnLabel: "CMC Invoice", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1DelNo', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "delNo", headerAlign: "center", align: "center", columnLabel: "发货通知单号", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 110 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1ReadyDate', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "readyDate", headerAlign: "center", align: "center", columnLabel: "ReadyDate", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1CustomerName', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "customerName", headerAlign: "center", align: "left", columnLabel: "客户名称", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 220 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1ShippingMode', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "shippingMode", headerAlign: "center", align: "left", columnLabel: "ShippingMode", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1Destination', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "destination", headerAlign: "center", align: "left", columnLabel: "Destination", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1NotifyStatus', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "notifyStatus", headerAlign: "center", align: "left", columnLabel: "通知单状态", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801001, serialNumber: '801001Table1NotifyStatus', tableId: "801001Table1", tableName: "关务系统发货通知单", columnProp: "modifyLabel", headerAlign: "center", align: "left", columnLabel: "改单", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 60 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1ExportFlag', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "exportFlag", headerAlign: "center", align: "center", columnLabel: "是否导出", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 80 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1NotifyDate', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "notifyDate", headerAlign: "center", align: "center", columnLabel: "发货日期", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 120 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1ErpDelNo', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "walMartOrderFlag", headerAlign: "center", align: "left", columnLabel: "沃尔玛订单", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1CreateBy', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "createBy", headerAlign: "center", align: "left", columnLabel: "创建人", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 80 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1CreateDate', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "createDate", headerAlign: "center", align: "center", columnLabel: "创建时间", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 130 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1UpdateBy', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "updateBy", headerAlign: "center", align: "left", columnLabel: "修改人", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 80 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1UpdateDate', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "updateDate", headerAlign: "center", align: "center", columnLabel: "修改时间", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 130 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table1Remark', tableId: "801002Table1", tableName: "关务系统发货通知单", columnProp: "remark", headerAlign: "center", align: "left", columnLabel: "Remark", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 300 }, ], columnList2: [ { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2ItemNo', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "itemNo", headerAlign: "center", align: "left", columnLabel: "行号", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 80 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2PartNo', tableId: "801002Table2", 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: '801002Table2PartDescription', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "partDescription", headerAlign: "center", align: "left", columnLabel: "Description", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 300 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2Qty', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "qty", headerAlign: "center", align: "right", columnLabel: "Qty (pcs)", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2SalesOrder', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "salesOrder", headerAlign: "center", align: "left", columnLabel: "销售订单号", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2CustomerPO', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "customerPO", headerAlign: "center", align: "left", columnLabel: "客户采购单号", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2Version', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "version", headerAlign: "center", align: "left", columnLabel: "Version", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2Status', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "status", headerAlign: "center", align: "left", columnLabel: "Status", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2Family', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "family", headerAlign: "center", align: "left", columnLabel: "Family", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2Lt', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "lt", headerAlign: "center", align: "right", columnLabel: "LT (wks)", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2CmcComment', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "cmcComment", headerAlign: "center", align: "left", columnLabel: "CMC Comment", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2SaleType', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "saleType", headerAlign: "center", align: "left", columnLabel: "内外销方式", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2AwbBl', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "awbBl", headerAlign: "center", align: "left", columnLabel: "AWB/ BL#", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2ShippingNumber', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "shippingNumber", headerAlign: "center", align: "left", columnLabel: "ShippingNumber", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2ForwarderInfo', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "forwarderInfo", headerAlign: "center", align: "left", columnLabel: "Forwarder Info", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2Currency', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "currency", headerAlign: "center", align: "left", columnLabel: "Currency", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2Tp', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "tp", headerAlign: "center", align: "right", columnLabel: "TP", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 80 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2TtlAmount', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "ttlAmount", headerAlign: "center", align: "right", columnLabel: "TTL Amount", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 80 }, { userId: this.$store.state.user.name, functionId: 801001, serialNumber: '801001Table2Remark', tableId: "801001Table2", tableName: "关务系统发货通知单明细", columnProp: "vat", headerAlign: "center", align: "right", columnLabel: "VAT", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2SumPrice', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "sumPrice", headerAlign: "center", align: "right", columnLabel: "价税合计", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 80 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2So', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "so", headerAlign: "center", align: "left", columnLabel: "SO", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2Upc', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "upc", headerAlign: "center", align: "left", columnLabel: "UPC", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table2Remark', tableId: "801002Table2", tableName: "关务系统发货通知单明细", columnProp: "remark", headerAlign: "center", align: "left", columnLabel: "Remark", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 300 }, { userId: this.$store.state.user.name, functionId: 801001, serialNumber: '801001Table2Remark', tableId: "801001Table2", tableName: "关务系统发货通知单明细", columnProp: "roll", headerAlign: "center", align: "right", columnLabel: "Roll", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801001, serialNumber: '801001Table2Remark', tableId: "801001Table2", tableName: "关务系统发货通知单明细", columnProp: "carton", headerAlign: "center", align: "right", columnLabel: "Carton", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801001, serialNumber: '801001Table2Remark', tableId: "801001Table2", tableName: "关务系统发货通知单明细", columnProp: "qtyRoll", headerAlign: "center", align: "right", columnLabel: "qty/roll", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, { userId: this.$store.state.user.name, functionId: 801001, serialNumber: '801001Table2Remark', tableId: "801001Table2", tableName: "关务系统发货通知单明细", columnProp: "qtyBox", headerAlign: "center", align: "right", columnLabel: "qty/box", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 100 }, ], 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 }, ],
columnList4:[ { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table4SeqNo', tableId: "801002Table4", tableName: "装箱栈板主表", columnProp: "seqNo", 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: '801002Table4PalletRemark', tableId: "801002Table4", tableName: "装箱栈板主表", columnProp: "palletRemark", headerAlign: "center", align: "left", columnLabel: "栈板码", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 60 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table4PalletQty', tableId: "801002Table4", tableName: "装箱栈板主表", columnProp: "palletQty", 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: '801002Table4PalletQty', tableId: "801002Table4", tableName: "装箱栈板主表", columnProp: "weight", headerAlign: "center", align: "right", columnLabel: "重量(KG)", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 50 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table4Length', tableId: "801002Table4", tableName: "装箱栈板主表", columnProp: "length", headerAlign: "center", align: "right", columnLabel: "长(M)", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 50 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table4Width', tableId: "801002Table4", tableName: "装箱栈板主表", columnProp: "width", headerAlign: "center", align: "right", columnLabel: "宽(M)", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 50 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table4Height', tableId: "801002Table4", tableName: "装箱栈板主表", columnProp: "height", headerAlign: "center", align: "right", columnLabel: "高(M)", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 50 }, ], columnList5:[ { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table5PartNo', tableId: "801002Table5", tableName: "栈板装箱明细", columnProp: "pn", headerAlign: "center", align: "left", columnLabel: "物料编码", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 70 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table5Qty', tableId: "801002Table5", tableName: "栈板装箱明细", columnProp: "qty", headerAlign: "center", align: "right", columnLabel: "数量", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 80 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table5BoxQty', tableId: "801002Table5", tableName: "栈板装箱明细", columnProp: "boxQty", headerAlign: "center", align: "right", columnLabel: "箱数", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 70 }, { userId: this.$store.state.user.name, functionId: 801002, serialNumber: '801002Table5Rolls', tableId: "801002Table5", tableName: "栈板装箱明细", columnProp: "rolls", headerAlign: "center", align: "right", columnLabel: "Rolls", columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 70 }, ],
ossColumns:[ { userId: this.$store.state.user.name, functionId: 103001, serialNumber: '103001Table2FileName', tableId: '103001Table2', tableName: '文件信息表', columnProp: 'fileName', headerAlign: 'center', align: 'center', columnLabel: '文件名称', columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 140 }, { userId: this.$store.state.user.name, functionId: 103001, serialNumber: '103001Table2FileRemark', tableId: '103001Table2', tableName: '文件信息表', columnProp: 'fileRemark', headerAlign: 'center', align: 'center', columnLabel: '备注', columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 240 }, { userId: this.$store.state.user.name, functionId: 103001, serialNumber: '103001Table2CreateDate', tableId: '103001Table2', tableName: '文件信息表', columnProp: 'createDate', headerAlign: 'center', align: 'center', columnLabel: '上传时间', columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 140 }, { userId: this.$store.state.user.name, functionId: 103001, serialNumber: '103001Table2CreatedBy', tableId: '103001Table2', tableName: '文件信息表', columnProp: 'createdBy', headerAlign: 'center', align: 'center', columnLabel: '上传人', columnHidden: false, columnImage: false, columnSortable: false, sortLv: 0, status: true, fixed: '', columnWidth: 140 } ], currentRow:{}, } }, mounted() { this.$nextTick(() => { this.height = (window.innerHeight - 260)/2; }) },
computed: { /** * 判断是否禁用总Rolls输入框 * 逻辑:只有当所有明细的rolls都是空或0时,才允许修改总rolls * @returns {boolean} true=禁用,false=启用 */ isTotalRollsDisabled() { // 检查是否有任何明细的 rolls 不为空且大于 0
const hasValidRolls = this.dataList8.some(item => { const rollsValue = parseFloat(item.rolls); return !isNaN(rollsValue) && rollsValue > 0; }); // 如果有任何明细有有效的rolls值,则禁用总rolls输入框
return hasValidRolls; },
/** * 合箱批量编辑修改数量 */ mergeBoxModifiedCount() { return Object.keys(this.mergeBoxModifiedBoxes).length + Object.keys(this.mergeBoxModifiedDetails).length; } },
methods: { // 动态列开始 获取 用户保存的 格式列
async getTableUserColumn (tableId, columnId) { let queryTableUser = { userId: this.$store.state.user.name, functionId: this.$route.meta.menuId, tableId: tableId, status: true, languageCode: this.$i18n.locale } await getTableUserListLanguage(queryTableUser).then(({data}) => { if (data.rows.length > 0) { //this.columnList1 = []
switch (columnId) { case 1: this.columnList1 = data.rows break; // case 2:
// this.columnDetailList = data.rows
// break;
// case 3:
// this.columnList2 = data.rows
// break;
// case 4:
// this.columnList3 = data.rows
// break;
} } else { this.getColumnList(tableId, columnId) } }) }, // 获取 tableDefault 列
async getColumnList (tableId, columnId) { let queryTable = { functionId: this.$route.meta.menuId, tableId: tableId, languageCode: this.$i18n.locale } await getTableDefaultListLanguage(queryTable).then(({data}) => { if (!data.rows.length == 0) { switch (columnId) { case 1: this.columnList1 = data.rows break; // case 2:
// this.columnDetailList = data.rows
// break;
// case 3:
// this.columnList2 = data.rows
// break;
// case 4:
// this.columnList3 = data.rows
// break;
} } else { // this.showDefault = true.
} }) }, isPnDataIncomplete(row) { const hasBoxrolls = row.boxrolls !== null && row.boxrolls !== undefined && row.boxrolls !== ''; const hasRollqty = row.rollqty !== null && row.rollqty !== undefined && row.rollqty !== ''; const hasBoxweight = row.boxweight !== null && row.boxweight !== undefined && row.boxweight !== ''; const packageNo = row.packageNo !== null && row.packageNo !== undefined && row.packageNo !== ''; return !hasBoxrolls || !hasRollqty || !hasBoxweight || !packageNo; },
// 获取PN数据缺失的具体字段提示信息
getPnIncompleteTooltip(row) { const missingFields = [];
// 检查每个字段是否缺失
if (!(row.rollqty !== null && row.rollqty !== undefined && row.rollqty !== '')) { missingFields.push('每卷数量'); } if (!(row.boxrolls !== null && row.boxrolls !== undefined && row.boxrolls !== '')) { missingFields.push('每箱卷数'); } if (!(row.boxweight !== null && row.boxweight !== undefined && row.boxweight !== '')) { missingFields.push('箱重量'); } if (!(row.packageNo !== null && row.packageNo !== undefined && row.packageNo !== '')) { missingFields.push('箱类型'); }
// 根据缺失字段生成提示信息
if (missingFields.length > 0) { return `基本信息(${missingFields.join('、')})未维护,点击跳转到维护页面`; } return ''; },
// 跳转到PN维护页面
navigateToPartHsCode(pn) { if (!pn) { this.$message.warning('PN不能为空'); return; } this.$router.push({ path: '/ecss-partHsCode', query: { sku: pn } }); },
openPartDialog () { this.searchPartList(); this.partFlag = true }, closePartDialog () { this.partList = [] this.partFlag = false }, searchPartList () { this.partData.site = this.currentRow.site this.partData.delNo = this.currentRow.delNo getNotifyPartDetail(this.partData).then(({data}) => { if (data && data.code === 0){ this.partList = data.rows; } }) }, partRowDblclick (row) { this.boxModelData.partNo = row.partNo this.boxModelData.pn = row.pn this.partFlag = false }, // 获取基础数据列表S
getBaseList(val, type) { this.tagNo = val this.$nextTick(() => { let strVal = '' if (val === 507) { strVal = this.boxModelData.partNo } this.$refs.baseList.init(val, strVal) }) },
/* 列表方法的回调 */ getBaseData(val) { if (this.tagNo === 507) { this.boxModelData.partNo = val.part_no } }, // 每页数
sizeChangeHandle (val) { this.pageSize = val this.pageIndex = 1 this.searchTable() }, // 当前页
currentChangeHandle (val) { this.pageIndex = val this.searchTable() }, searchTable(){ this.searchData.limit = this.pageSize this.searchData.page = this.pageIndex searchEcssCoDelNotifyHeaderForCK(this.searchData).then(({data}) => { //区分请求成功和失败的状况
if (data && data.code == 0) { this.dataList = data.page.list this.pageIndex = data.page.currPage this.pageSize = data.page.pageSize this.totalPage = data.page.totalCount if(this.dataList.length>0){ this.dataList.forEach(o => { if (o.notifyStatus==='仓库已确认'&&!o.notifyDate) { o.notifyDate='发货日期不确定' } // 显示改单次数,如:改单(1)、改单(2)
o.modifyLabel = !!o.modifyFlag ? (o.modifyCount ? '改单(' + o.modifyCount + ')' : '改单(1)') : ''; });
// 使用 $nextTick 确保 DOM 渲染完成后再设置选中行
this.$nextTick(() => { try { // 检查表格引用是否存在
if (!this.$refs.mainTable) { console.warn('[确认页面行选择持久化] 表格引用不存在,跳过设置选中行'); return; }
// 尝试恢复之前选中的行
const restoredRow = this.restoreSelectedRow(); if (restoredRow) { this.$refs.mainTable.setCurrentRow(restoredRow); this.changeData(restoredRow); } else { // 如果没有之前选中的行,默认选中第一行
this.$refs.mainTable.setCurrentRow(this.dataList[0]); this.changeData(this.dataList[0]); } } catch (error) { console.error('[确认页面行选择持久化] 设置选中行失败:', error); // 降级处理:只调用 changeData,不设置表格选中状态
const restoredRow = this.restoreSelectedRow(); this.changeData(restoredRow || this.dataList[0]); } }); }else { this.changeData(null) } } else { this.dataList = []; } }); }, tableRowClassName({row}) { if (row.notifyStatus==='订单取消') { return 'warning-row'; } }, cellStyle({row, column }) { if (column.property === 'notifyDate' && row.notifyDate==='发货日期不确定') { // 根据列属性判断
return { color: '#ff5d03' }; } // 改单列显示橙色:只要modifyFlag为true就显示橙色
if (column.property === 'modifyLabel' && row.modifyFlag===true) { return { color: '#ff5d03' }; } return {}; }, cellStyleDetail({row, column }) { // 只有数量列且 modifyQtyFlag=true 时才变色
if (column.property === 'qty' && row.modifyQtyFlag===true) { return { color: '#ff5d03' }; }
// PN列保持原有的 modifyFlag 判断
if (column.property === 'pn' && row.modifyFlag===true) { return { color: '#ff5d03' }; }
// 检查 pn 列,当 boxrolls、rollqty、boxweight 其中任意一个没有值时,将 pn 颜色改成橙色
if (column.property === 'pn') { const hasBoxrolls = row.boxrolls !== null && row.boxrolls !== undefined && row.boxrolls !== ''; const hasRollqty = row.rollqty !== null && row.rollqty !== undefined && row.rollqty !== ''; const hasBoxweight = row.boxweight !== null && row.boxweight !== undefined && row.boxweight !== ''; const packageNo = row.packageNo !== null && row.packageNo !== undefined && row.packageNo !== ''; if (!hasBoxrolls || !hasRollqty || !hasBoxweight || !packageNo) { return { color: '#ff8c00' }; // 橙色
} }
return {}; }, changeData(row){ this.currentRow = JSON.parse(JSON.stringify(row)); if (this.currentRow&&this.currentRow.notifyDate==='发货日期不确定') { this.currentRow.notifyDate='' } this.headerData=row;
// 保存选中行的唯一标识到本地存储
if (row && row.delNo) { this.selectedRowKey = row.delNo; this.saveSelectedRowToStorage(); }
this.refreshCurrentTabTable (); }, refreshCurrentTabTable(){ if(this.currentRow===''||this.currentRow===null){ this.currentRow={site:'',delNo:'',notifyStatus:''} } if(this.activeName==='detail'){ searchEcssCoDelNotifyDetail(this.currentRow).then(({data}) => { //区分请求成功和失败的状况
if (data && data.code == 0) { this.dataList2 = data.rows } else { this.dataList2 = []; } }); } if(this.activeName==='pallet'){ // 刷新装箱明细组件
if (this.$refs.packingDetailTab) { this.$refs.packingDetailTab.refresh(); } } if(this.activeName==='box'){ searchEcssCoDelPalletHeaderData(this.currentRow).then(({data}) => { //区分请求成功和失败的状况
if (data && data.code == 0) { this.dataList4 = data.rows
} else { this.dataList4 = []; } }); } }, tabClick (tab, event) { // 刷新列表数据
this.refreshCurrentTabTable() },
confirmDo(){ confirmEcssDel(this.confirmModel).then(({data}) => { if (data && data.code === 0) { // 保存当前选中行的标识,以便刷新后恢复
const currentSelectedKey = this.confirmModel ? this.confirmModel.delNo : null; if (currentSelectedKey) { this.selectedRowKey = currentSelectedKey; this.saveSelectedRowToStorage(); } this.searchTable() this.confirmModelFlag=false this.$message({ message: '操作成功', type: 'success', duration: 1500, onClose: () => {} }) } else { this.$alert(data.msg, '错误', { confirmButtonText: '确定' }) } }) }, cancerConfirm(row){ let indata=JSON.parse(JSON.stringify(row)); if (row.notifyDate==='发货日期不确定') { indata.notifyDate='' } this.$confirm('取消确认这条发货通知单?', '提示').then(() => { cancerConfirmEcssDel(indata).then(({data}) => { if (data && data.code === 0) { // 保存当前选中行的标识,以便刷新后恢复
const currentSelectedKey = row ? row.delNo : null; if (currentSelectedKey) { this.selectedRowKey = currentSelectedKey; this.saveSelectedRowToStorage(); } this.searchTable() this.$message({ message: '操作成功', type: 'success', duration: 1500, onClose: () => {} }) } else { this.$alert(data.msg, '错误', { confirmButtonText: '确定' }) } }) }) }, getBu () { let tempData = { username: this.$store.state.user.name, } getBuList(tempData).then(({data}) => { if (data.code === 0) { this.buList = data.row2 if (this.buList.length===1) { this.searchData.buNo = this.buList[0].buNo; } } }) }, confirmModelOpen(row){ this.confirmModel=JSON.parse(JSON.stringify(row)); this.confirmModelFlag=true }, updateModelOpen(row){ this.confirmModel=JSON.parse(JSON.stringify(row)); if (this.confirmModel.notifyDate==='发货日期不确定') { this.confirmModel.notifyDate='' } this.updateModelFlag=true }, updateDo(){ if (!this.confirmModel.readyDate) { this.$alert('请选择ReadyDate!', '错误', { confirmButtonText: '确定' }) return false } // 添加更新人信息
this.confirmModel.updateBy = this.$store.state.user.name updateEcssDel(this.confirmModel).then(({data}) => { if (data && data.code === 0) { // 保存当前选中行的标识,以便刷新后恢复
const currentSelectedKey = this.confirmModel ? this.confirmModel.delNo : null; if (currentSelectedKey) { this.selectedRowKey = currentSelectedKey; this.saveSelectedRowToStorage(); } this.searchTable() this.updateModelFlag=false this.$message({ message: '操作成功', type: 'success', duration: 1500, onClose: () => {} }) } else { this.$alert(data.msg, '错误', { confirmButtonText: '确定' }) } }) }, upLoadPallet(){ if(this.currentRow.site===''||this.currentRow.site==null){ this.$alert('请先选择发货通知单!', '错误', { confirmButtonText: '确定' }) return false } let inData={ site:this.currentRow.site, buNo:this.currentRow.buNo, delNo:this.currentRow.delNo, cmcInvoice:this.currentRow.cmcInvoice, shippingMode: this.currentRow.shippingMode, destination : this.currentRow.destination, walMartOrderFlag:this.currentRow.walMartOrderFlag } this.$nextTick(() => { this.$refs.palletUploadExcel.init(inData) }) }, async exportExcel() { if(this.currentRow.site===''||this.currentRow.site==null){ this.$alert('请先选择发货通知单!', '错误', { confirmButtonText: '确定' }) return false }
let exportParam = { site: this.currentRow.site, buNo: this.currentRow.buNo, delNo: this.currentRow.delNo, cmcInvoice: this.currentRow.cmcInvoice, shippingMode: this.currentRow.shippingMode, destination : this.currentRow.destination, readyDate: this.currentRow.readyDate, // 增加ReadyDate列
remark: this.currentRow.remark, // 增加备注列
createBy: this.$store.state.user.name, }
try { // 使用后台Excel模版导出
ExportUtil.export( "/ecss/coDel/exportPackingTemplate", exportParam, this.currentRow.cmcInvoice + "装箱数据.xlsx" );
// 导出成功后更新export_flag字段
let updateData = { site: this.currentRow.site, buNo: this.currentRow.buNo, delNo: this.currentRow.delNo, exportFlag: 'Y', updateBy: this.$store.state.user.name }
updateExportFlag(updateData).then(({data}) => { if (data.code === 0) { // 刷新当前行的导出状态
this.currentRow.exportFlag = 'Y'; // 刷新表格数据
this.searchTable(); this.$message({ message: '导出成功', type: 'success', duration: 1500 }); } else { this.$message.warning('导出成功,但更新导出状态失败:' + data.msg); } }).catch(error => { this.$message.warning('导出成功,但更新导出状态失败'); console.error('更新导出状态失败:', error); });
} catch (error) { this.$message.error('导出失败'); console.error('导出失败:', error); } }, searchPalletTable(){ this.refreshCurrentTabTable(); }, boxDetailModel(row){ this.boxDetailData=row searchEcssCoDelPalletDetailData(row).then(({data}) => { if (data.code === 0) { this.dataList5 = data.rows } }) this.boxDetailModelFlag=true }, updatePalletModel(row){ this.palletModelData=JSON.parse(JSON.stringify(row)) this.palletModelData.palletRemark=row.palletRemark this.palletModelData.addFlag=1 this.palletEditFlag=true }, newPalletModel(){ if(this.currentRow.site===''||this.currentRow.site==null){ this.$alert('请先选择发货通知单!', '错误', { confirmButtonText: '确定' }) return false } this.palletModelData={ addFlag:0, site:this.currentRow.site, buNo:this.currentRow.buNo, delNo:this.currentRow.delNo, grossWeight:'', netWeight:'', boxQty:'', } searchEcssCoDelNotifyDetail(this.currentRow).then(({data}) => { if (data && data.code == 0) { this.dataList8 = data.rows } else { this.dataList8 = []; } }); this.palletModelFlag=true }, fillUseQty(row) { row.useQty = row.surplusQty || 0; // 全数装箱后也需要计算rolls
this.calculateRolls(row); }, /** * 根据装箱数量自动计算Rolls(卷数) * 计算公式:Rolls = 装箱数量 / 每卷数量 * @param row 当前行数据 */ calculateRolls(row) { // 如果装箱数量为空或为0,清空rolls
if (!row.useQty || row.useQty <= 0) { this.$set(row, 'rolls', null); // 装箱数量变化后,重新计算总箱数和重量
this.calculateTotalBoxQtyAndWeights(); return; }
// 如果已经有缓存的每卷数量,直接计算
if (row.rollQtyCache && row.rollQtyCache > 0) { const rolls = row.useQty / row.rollQtyCache; this.$set(row, 'rolls', parseFloat(rolls.toFixed(4))); // 装箱数量变化后,重新计算总箱数和重量
this.calculateTotalBoxQtyAndWeights(); return; }
// 调用后端API获取每卷数量
const params = { site: this.currentRow.site, buNo: this.currentRow.buNo, partNo: row.partNo };
getPartPackageProperties(params).then(({data}) => { if (data && data.code === 0 && data.data) { const rollQty = data.data.rollQty;
if (rollQty && rollQty > 0) { // 缓存每卷数量到row中,避免重复请求
this.$set(row, 'rollQtyCache', rollQty); this.$set(row, 'boxRollsCache', data.data.boxRolls); this.$set(row, 'boxWeightCache', data.data.boxWeight);
// 计算rolls:装箱数量 / 每卷数量
const rolls = row.useQty / rollQty; this.$set(row, 'rolls', parseFloat(rolls.toFixed(4)));
// 装箱数量变化后,重新计算总箱数和重量
this.calculateTotalBoxQtyAndWeights(); } else { this.$message.warning(`物料 ${row.partNo} 未配置每卷数量(ROLLQTY)属性,无法自动计算Rolls`); this.$set(row, 'rolls', null); } } else { console.error('获取物料包装属性失败:', data ? data.msg : '未知错误'); // 失败时不阻断用户操作,允许手动输入
this.$set(row, 'rolls', null); } }).catch(error => { console.error('获取物料包装属性异常:', error); // 异常时不阻断用户操作,允许手动输入
this.$set(row, 'rolls', null); }); }, /** * 根据物料装箱数量自动计算总箱数、毛重、净重和总Rolls */ calculateTotalBoxQtyAndWeights() { // 获取有装箱数量的物料列表
const selectedRows = this.dataList8.filter(item => item.useQty && item.useQty > 0);
// 先计算总Rolls(不管是否有缓存属性,都可以汇总)
this.calculateTotalRolls();
if (selectedRows.length === 0) { // 没有装箱数量时,清空
this.palletModelData.boxQty = null; this.palletModelData.grossWeight = null; this.palletModelData.netWeight = null; return; }
// 检查是否所有物料都已缓存包装属性
const allHaveCache = selectedRows.every(row => row.rollQtyCache && row.boxRollsCache && row.boxWeightCache );
if (!allHaveCache) { // 如果有物料未缓存属性,不自动计算(避免数据不完整)
return; }
// 计算总箱数和总重量
let totalBoxQty = 0; let totalGrossWeight = 0;
selectedRows.forEach(row => { // 每箱EA = 每卷数量 × 每箱卷数
const eaPerBox = row.rollQtyCache * row.boxRollsCache; // 该物料的箱数(向上取整)
const partBoxQty = Math.ceil(row.useQty / eaPerBox); // 该物料的毛重 = 箱数 × 箱重量
const partGrossWeight = partBoxQty * row.boxWeightCache;
totalBoxQty += partBoxQty; totalGrossWeight += partGrossWeight; });
// 净重 = 毛重 - (箱数 / 2)
const totalNetWeight = totalGrossWeight - (totalBoxQty / 2);
// 自动填入箱数、毛重、净重
this.palletModelData.boxQty = totalBoxQty; this.palletModelData.grossWeight = parseFloat(totalGrossWeight.toFixed(2)); this.palletModelData.netWeight = parseFloat(totalNetWeight.toFixed(2)); },
/** * 汇总明细的Rolls总和 */ calculateTotalRolls() { let totalRolls = 0; this.dataList8.forEach(row => { const rollsValue = parseFloat(row.rolls); if (!isNaN(rollsValue) && rollsValue > 0) { totalRolls += rollsValue; } }); // 自动填入总Rolls(取整)
this.$set(this.palletModelData, 'rolls', totalRolls > 0 ? Math.round(totalRolls) : null); },
/** * 延迟计算总Rolls(等待v-model更新完成) */ delayCalculateTotalRolls() { this.$nextTick(() => { this.calculateTotalRolls(); }); }, /** * 根据箱数自动计算毛重和净重 * 计算公式(来自后端代码2991-2992行): * 毛重 = 箱数 × 箱重量 * 净重 = 毛重 - (箱数 / 2) */ calculateWeightsByBoxQty() { // 如果箱数为空或为0,清空毛重和净重
if (!this.palletModelData.boxQty || this.palletModelData.boxQty <= 0) { this.palletModelData.grossWeight = null; this.palletModelData.netWeight = null; return; }
// 获取有装箱数量的物料列表
const selectedRows = this.dataList8.filter(item => item.useQty && item.useQty > 0);
if (selectedRows.length === 0) { // 没有选择物料时,不自动计算,允许用户手动输入
return; }
// 检查是否所有物料都已缓存箱重量
const needFetchProperties = selectedRows.filter(row => !row.boxWeightCache);
if (needFetchProperties.length === 0) { // 所有物料都有缓存,直接计算
this.calculateWeightsWithCache(selectedRows); } else { // 需要获取部分物料的属性
this.fetchBoxWeightsAndCalculate(selectedRows, needFetchProperties); } }, /** * 使用缓存的箱重量计算毛重和净重 */ calculateWeightsWithCache(selectedRows) { // 根据装箱数量计算加权平均箱重量
let totalWeight = 0; let totalQty = 0;
selectedRows.forEach(row => { if (row.boxWeightCache && row.boxWeightCache > 0 && row.rollQtyCache && row.rollQtyCache > 0 && row.boxRollsCache && row.boxRollsCache > 0) { // 每箱EA = 每卷数量 × 每箱卷数
const eaPerBox = row.rollQtyCache * row.boxRollsCache; // 该物料的箱数
const partBoxQty = Math.ceil(row.useQty / eaPerBox); // 累计重量和箱数
totalWeight += partBoxQty * row.boxWeightCache; totalQty += partBoxQty; } });
if (totalQty > 0) { // 计算平均箱重量
const avgBoxWeight = totalWeight / totalQty; this.calculateFinalWeights(avgBoxWeight); } else { // 如果无法计算平均重量,使用第一个物料的箱重量
const firstRow = selectedRows.find(row => row.boxWeightCache && row.boxWeightCache > 0); if (firstRow) { this.calculateFinalWeights(firstRow.boxWeightCache); } } }, /** * 获取物料箱重量并计算毛重净重 */ fetchBoxWeightsAndCalculate(selectedRows, needFetchProperties) { // 批量获取物料属性
const promises = needFetchProperties.map(row => { const params = { site: this.currentRow.site, buNo: this.currentRow.buNo, partNo: row.partNo }; return getPartPackageProperties(params).then(({data}) => { if (data && data.code === 0 && data.data) { // 缓存物料属性
this.$set(row, 'rollQtyCache', data.data.rollQty); this.$set(row, 'boxRollsCache', data.data.boxRolls); this.$set(row, 'boxWeightCache', data.data.boxWeight); return true; } return false; }).catch(error => { console.error(`获取物料 ${row.partNo} 属性失败:`, error); return false; }); });
Promise.all(promises).then(() => { // 所有属性获取完成后,重新计算
this.calculateWeightsWithCache(selectedRows); }); }, /** * 计算最终的毛重和净重 * @param avgBoxWeight 平均箱重量 */ calculateFinalWeights(avgBoxWeight) { const boxQty = parseFloat(this.palletModelData.boxQty);
// 毛重 = 箱数 × 箱重量
const grossWeight = boxQty * avgBoxWeight;
// 净重 = 毛重 - (箱数 / 2)
const netWeight = grossWeight - (boxQty / 2);
// 保留2位小数
this.palletModelData.grossWeight = parseFloat(grossWeight.toFixed(2)); this.palletModelData.netWeight = parseFloat(netWeight.toFixed(2)); },
/** * 毛重改变时自动计算净重 * 计算公式:净重 = 毛重 - (箱数 / 2) */ onPalletGrossWeightChange(value) { // 防止循环触发,使用标志位
if (this._isPalletWeightCalculating) { return; }
this._isPalletWeightCalculating = true;
try { const grossWeight = parseFloat(value) || 0; const boxQty = parseFloat(this.palletModelData.boxQty) || 0;
if (grossWeight <= 0) { this.palletModelData.netWeight = ''; return; }
// 计算净重:净重 = 毛重 - (箱数 / 2)
const netWeight = grossWeight - (boxQty / 2);
// 保留2位小数
this.palletModelData.netWeight = parseFloat(netWeight.toFixed(2)); } finally { this._isPalletWeightCalculating = false; } },
/** * 净重改变时自动计算毛重 * 反向计算公式:毛重 = 净重 + (箱数 / 2) */ onPalletNetWeightChange(value) { // 防止循环触发,使用标志位
if (this._isPalletWeightCalculating) { return; }
this._isPalletWeightCalculating = true;
try { const netWeight = parseFloat(value) || 0; const boxQty = parseFloat(this.palletModelData.boxQty) || 0;
if (netWeight <= 0) { this.palletModelData.grossWeight = ''; return; }
// 反向计算毛重:毛重 = 净重 + (箱数 / 2)
const grossWeight = netWeight + (boxQty / 2);
// 保留2位小数
this.palletModelData.grossWeight = parseFloat(grossWeight.toFixed(2)); } finally { this._isPalletWeightCalculating = false; } }, savePalletHeader(type) { // 过滤出 useQty > 0 的行
const selectedRows = this.dataList8.filter(item => item.useQty && item.useQty > 0);
if (this.palletModelData.addFlag === 0 && selectedRows.length === 0) { this.$alert('请至少输入一行装箱数量!', '错误', { confirmButtonText: '确定' }); return false; } if (this.palletModelData.grossWeight<=0||this.palletModelData.grossWeight==null) { this.$alert('请输入毛重!', '错误', { confirmButtonText: '确定' }); return false;
} if (this.palletModelData.netWeight<=0||this.palletModelData.netWeight==null) { this.$alert('请输入净重!', '错误', { confirmButtonText: '确定' }); return false; } if (this.palletModelData.boxQty<=0||this.palletModelData.boxQty==null) { this.$alert('请输入箱数!', '错误', { confirmButtonText: '确定' }); return false; } // 校验:装箱数量不能大于可装箱数量 (item.qty)
const invalidRow = selectedRows.find(item => item.useQty > item.surplusQty); if (invalidRow) { this.$alert(`PN ${invalidRow.pn} 的装箱数量不能大于可装箱数量(${invalidRow.surplusQty})!`, '错误', { confirmButtonText: '确定' }); return false; }
this.palletModelData.walMartOrderFlag = this.currentRow.walMartOrderFlag; this.palletModelData.notifyDetailList = selectedRows;
savePalletHeader(this.palletModelData).then(({ data }) => { if (data && data.code === 0) { if (type===0) { this.palletModelData={ addFlag:0, site:this.currentRow.site, buNo:this.currentRow.buNo, delNo:this.currentRow.delNo, grossWeight:'', netWeight:'', boxQty:'', } searchEcssCoDelNotifyDetail(this.currentRow).then(({data}) => { if (data && data.code == 0) { this.dataList8 = data.rows } else { this.dataList8 = []; } }); } else { this.refreshCurrentTabTable() this.palletModelFlag=false; } this.$message({ message: '操作成功', type: 'success', duration: 1500 }); } else { this.$alert(data.msg, '错误', { confirmButtonText: '确定' }); } }); },
updateCodelPalletHeaderPalletQty(row){ // 显示页面loading
const loading = this.$loading({ lock: true, text: '保存中...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.3)' });
updateCodelPalletHeaderPalletQty(this.palletModelData).then(({data}) => { loading.close(); if (data && data.code === 0) { this.palletEditFlag = false // 刷新当前tab表格
this.refreshCurrentTabTable() // 刷新上方的发货通知单列表
this.searchTable() this.$message({ message: '操作成功', type: 'success', duration: 1500, onClose: () => {} }) } else { this.$alert(data.msg, '错误', { confirmButtonText: '确定' }) } }).catch(error => { loading.close(); this.$message.error('保存失败: ' + (error.message || '未知错误')) }) },
deletePallet(row){ this.$confirm('确认删除此明细?', '提示').then(() => { // 显示页面loading
const loading = this.$loading({ lock: true, text: '删除中...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.3)' });
deletePalletHeader(row).then(({data}) => { loading.close(); if (data && data.code === 0) { this.refreshCurrentTabTable() // 刷新上方的发货通知单列表
this.searchTable() this.$message({ message: '操作成功', type: 'success', duration: 1500, onClose: () => {} }) } else { this.$alert(data.msg, '错误', { confirmButtonText: '确定' }) } }).catch(error => { loading.close(); this.$message.error('删除失败: ' + (error.message || '未知错误')) }) }) },
updateBoxModel(row,type){ this.boxModelData=JSON.parse(JSON.stringify(row)) this.boxModelData.addFlag=1 this.boxModelData.type=type this.boxModelFlag=true }, newBoxModel(){ this.boxModelData={ addFlag:0, site:this.boxDetailData.site, buNo:this.boxDetailData.buNo, delNo:this.boxDetailData.delNo, seqNo:this.boxDetailData.seqNo, itemNo:'', partNo:'', pn:'', qty:'', poNo:'', boxQty:'', rolls:'', type:0 } this.boxModelFlag=true }, saveBoxHeader(){ if(this.boxModelData.partNo===''||this.boxModelData.partNo==null){ this.$alert('请输入物料!', '错误', { confirmButtonText: '确定' }) return false } if(this.boxModelData.qty<=0||this.boxModelData.qty==null){ this.$alert('请输入数量!', '错误', { confirmButtonText: '确定' }) return false }
savePalletDetail(this.boxModelData).then(({data}) => { if (data && data.code === 0) { searchEcssCoDelPalletDetailData(this.boxDetailData).then(({data}) => { if (data.code === 0) { this.dataList5 = data.rows } }) searchCoDelPalletDataNew(this.currentRow).then(({data}) => { if (data && data.code == 0) { this.dataList3 = data.rows } else { this.dataList3 = []; } }); this.boxModelFlag=false; this.$message({ message: '操作成功', type: 'success', duration: 1500, onClose: () => {} }) } else { this.$alert(data.msg, '错误', { confirmButtonText: '确定' }) } }) },
oneClickPacking(){ if(this.currentRow.site===''||this.currentRow.site==null){ this.$alert('请先选择发货通知单!', '错误', { confirmButtonText: '确定' }) return false } this.oneClickPackingModelData={ boxRemnant: false, } this.oneClickPackingModelFlag=true }, saveOneClickPacking(){ let saveData = { site: this.currentRow.site, buNo: this.currentRow.buNo, delNo: this.currentRow.delNo, boxRemnant: this.oneClickPackingModelData.boxRemnant, }
// 显示页面loading
const loading = this.$loading({ lock: true, text: '一键装箱计算中...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.3)' });
saveOneClickPacking(saveData).then(({data}) => { loading.close(); if (data && data.code === 0) { this.oneClickPackingModelFlag=false; // 刷新当前tab表格
this.refreshCurrentTabTable() // 刷新上方的发货通知单列表
this.searchTable() this.$message({ message: '操作成功', type: 'success', duration: 1500, onClose: () => {} }) } else { this.$alert(data.msg, '错误', { confirmButtonText: '确定' }) } }).catch(error => { loading.close(); this.$message.error('一键装箱失败: ' + (error.message || '未知错误')) }) },
// ========== 合箱批量编辑相关方法 ==========
/** * 打开合箱批量编辑弹出框 */ openMergeBoxDialog() { if(this.currentRow.site===''||this.currentRow.site==null){ this.$alert('请先选择发货通知单!', '错误', { confirmButtonText: '确定' }) return false } this.mergeBoxDialogVisible = true },
/** * 加载合箱批量编辑数据 * 将发货通知单明细扁平化为表格数据,每条明细默认是一个箱子 */ async loadMergeBoxData() { this.mergeBoxLoading = true this.mergeBoxTableData = [] this.mergeBoxSelection = [] this.mergeBoxOriginalData = {} this.mergeBoxModifiedBoxes = {} this.mergeBoxModifiedDetails = {} this.mergeBoxMergeHistory = [] this.nextItemNo = 1
try { // 每次都重新查询最新的发货通知单明细数据
const detailResponse = await searchEcssCoDelNotifyDetail(this.currentRow) const detailList = (detailResponse.data && detailResponse.data.code === 0) ? detailResponse.data.rows || [] : []
if (detailList.length === 0) { this.$message.warning('当前发货通知单没有明细数据') this.mergeBoxLoading = false return }
// 处理明细数据 - 每条明细作为一个单独的箱
const tableData = [] let itemNo = 1
// 只处理剩余数量(surplus_qty)大于0的明细
const detailsToProcess = [] detailList.forEach(detail => { const surplusQty = Number(detail.surplusQty) || 0
// 只处理剩余数量大于0的明细
if (surplusQty > 0) { detailsToProcess.push({ detail: detail, unpackedQty: surplusQty // 使用剩余数量
}) } })
if (detailsToProcess.length === 0) { this.$message.warning('所有明细都已装箱完毕') this.mergeBoxLoading = false return }
// 创建表格数据
// searchEcssCoDelNotifyDetail已经返回了rollqty、boxrolls、boxweight,直接使用
detailsToProcess.forEach(({detail, unpackedQty}) => { const boxKey = `box_${itemNo}`
// 直接从detail中读取包装属性(小写字段名)
const rollQty = Number(detail.rollqty) || 0 const boxRolls = Number(detail.boxrolls) || 0 const boxWeight = Number(detail.boxweight) || 0
// 计算默认值
let detailRolls = 0 let box_qty = 1 let grossWeight = 0 let netWeight = 0 let rolls = 0
// 1. 根据数量计算明细rolls(与calculateRolls保持一致)
if (rollQty > 0) { detailRolls = parseFloat((unpackedQty / rollQty).toFixed(4)) // 总rolls = 明细rolls四舍五入取整(初始时每箱只有一条明细)
rolls = Math.round(detailRolls) }
// 2. 根据数量计算箱数
if (rollQty > 0 && boxRolls > 0) { const eaPerBox = rollQty * boxRolls box_qty = Math.ceil(unpackedQty / eaPerBox) }
// 3. 根据箱数计算毛重
if (boxWeight > 0) { grossWeight = parseFloat((box_qty * boxWeight).toFixed(3)) }
// 4. 根据毛重计算净重(与装箱按钮保持一致)
netWeight = parseFloat((grossWeight - (box_qty / 2)).toFixed(3))
// 创建一行数据(Box和明细合并在一起)
const rowData = { // Box信息
_boxKey: boxKey, _isFirstRowOfBox: true, _rowSpan: 1, item_no: itemNo, box_qty: box_qty, grossWeight: grossWeight, netWeight: netWeight, rolls: rolls, // 明细信息
_detailKey: `${detail.itemNo}_${detail.customerPO}_${detail.pn}`, _hasDetail: true, itemNo: detail.itemNo, poNo: detail.customerPO, pn: detail.pn, qty: unpackedQty, detailRolls: detailRolls, readyDate: detail.readyDate, partDesc: detail.partDesc, // 缓存物料属性(用于后续自动计算)
rollQtyCache: rollQty, boxRollsCache: boxRolls, boxWeightCache: boxWeight }
tableData.push(rowData)
// 保存Box原始数据
this.mergeBoxOriginalData[boxKey] = { box_qty: box_qty, grossWeight: grossWeight, netWeight: netWeight, rolls: rolls, boxWeight: boxWeight }
// 保存明细原始数据
this.mergeBoxOriginalData[rowData._detailKey] = { qty: unpackedQty, detailRolls: detailRolls }
itemNo++ })
this.mergeBoxTableData = tableData this.nextItemNo = itemNo
} catch (error) { console.error('加载合箱数据失败:', error) this.$message.error('加载数据失败') } finally { this.mergeBoxLoading = false } },
/** * 选择变化事件处理 */ handleMergeBoxSelectionChange(selection) { this.mergeBoxSelection = selection },
/** * 合并选中的箱 */ doMergeBoxes() { if (this.mergeBoxSelection.length < 2) { this.$message.warning('请至少选择2个箱进行合并') return }
// 获取选中箱的所有行数据
const selectedBoxKeys = this.mergeBoxSelection.map(row => row._boxKey) const rowsToMerge = this.mergeBoxTableData.filter(row => selectedBoxKeys.includes(row._boxKey) )
// 保存合并前的状态(用于取消合并)
const mergeHistoryItem = { timestamp: Date.now(), boxes: [] }
// 记录每个被合并的箱的原始状态
selectedBoxKeys.forEach(boxKey => { const boxRows = this.mergeBoxTableData.filter(row => row._boxKey === boxKey) if (boxRows.length > 0) { mergeHistoryItem.boxes.push({ boxKey: boxKey, item_no: boxRows[0].item_no, box_qty: boxRows[0].box_qty, grossWeight: boxRows[0].grossWeight, netWeight: boxRows[0].netWeight, rolls: boxRows[0].rolls, rowCount: boxRows.length, details: boxRows.map(r => ({ _detailKey: r._detailKey, itemNo: r.itemNo, poNo: r.poNo, pn: r.pn, qty: r.qty, detailRolls: r.detailRolls })) }) } })
this.mergeBoxMergeHistory.push(mergeHistoryItem)
// 使用第一个箱的序号作为合并后的序号
const targetItemNo = this.mergeBoxSelection[0].item_no const targetBoxKey = this.mergeBoxSelection[0]._boxKey
// 计算合并后的累加值
let totalBoxQty = 0 let totalGrossWeight = 0 let totalNetWeight = 0 let totalRolls = 0
// 按箱Key分组,计算每个箱的值
const boxMap = new Map() rowsToMerge.forEach(row => { if (!boxMap.has(row._boxKey)) { boxMap.set(row._boxKey, { box_qty: parseFloat(row.box_qty) || 0, grossWeight: parseFloat(row.grossWeight) || 0, netWeight: parseFloat(row.netWeight) || 0, rolls: parseFloat(row.rolls) || 0 }) } })
// 累加所有箱的值
boxMap.forEach(boxData => { totalBoxQty += boxData.box_qty totalGrossWeight += boxData.grossWeight totalNetWeight += boxData.netWeight })
// 累加所有明细的rolls
rowsToMerge.forEach(row => { if (row.detailRolls && row.detailRolls > 0) { totalRolls += parseFloat(row.detailRolls) } })
// 四舍五入取整(与装箱按钮保持一致)
const finalRolls = Math.round(totalRolls)
// 更新所有被合并的行
rowsToMerge.forEach((row, index) => { row.item_no = targetItemNo row._boxKey = targetBoxKey row._isFirstRowOfBox = index === 0 row._rowSpan = index === 0 ? rowsToMerge.length : 0
// 所有行使用累加后的值
row.box_qty = totalBoxQty row.grossWeight = parseFloat(totalGrossWeight.toFixed(3)) row.netWeight = parseFloat(totalNetWeight.toFixed(3)) row.rolls = finalRolls })
// 合并后重新编号所有箱
this.renumberBoxes()
// 按序号重新排序表格数据
this.sortTableDataByItemNo()
// 清空选择
this.$refs.mergeBoxTable.clearSelection() this.mergeBoxSelection = []
this.$message.success(`已合并 ${selectedBoxKeys.length} 个箱(箱数: ${totalBoxQty}, 毛重: ${totalGrossWeight.toFixed(3)}, 净重: ${totalNetWeight.toFixed(3)}),当前共 ${this.getUniqueBoxCount()} 个箱`) },
/** * 取消选中箱的合并 */ doUnmergeSelectedBoxes() { if (this.mergeBoxSelection.length === 0) { this.$message.warning('请先选择要取消合并的箱') return }
const selectedBoxKeys = this.mergeBoxSelection.map(row => row._boxKey)
// 找到选中箱的所有明细
const rowsToUnmerge = this.mergeBoxTableData.filter(row => selectedBoxKeys.includes(row._boxKey) && row._hasDetail )
if (rowsToUnmerge.length === 0) { this.$message.warning('所选箱没有明细数据') return }
// 获取原箱的序号,用于为新箱分配临时序号
const originalItemNo = rowsToUnmerge[0].item_no
// 为每条明细创建独立的箱,恢复成初始化时的原始数据
const newRows = [] rowsToUnmerge.forEach((row, index) => { const newBoxKey = `box_${Date.now()}_${index}`
// 从mergeBoxOriginalData恢复该明细的原始数据
const detailOriginalData = this.mergeBoxOriginalData[row._detailKey]
let box_qty, grossWeight, netWeight, rolls, detailRolls
// 始终使用缓存的包装属性重新计算(确保恢复到初始值)
const rollQty = row.rollQtyCache || 0 const boxRolls = row.boxRollsCache || 0 const boxWeight = row.boxWeightCache || 0 const qty = row.qty || 0
// 恢复明细rolls
if (detailOriginalData && detailOriginalData.detailRolls !== undefined) { detailRolls = detailOriginalData.detailRolls } else if (rollQty > 0) { detailRolls = parseFloat((qty / rollQty).toFixed(4)) } else { detailRolls = 0 }
// 计算总rolls(初始时每箱只有一条明细)
rolls = Math.round(detailRolls)
// 计算箱数
if (rollQty > 0 && boxRolls > 0) { const eaPerBox = rollQty * boxRolls box_qty = Math.ceil(qty / eaPerBox) } else { box_qty = 1 }
// 计算毛重
if (boxWeight > 0) { grossWeight = parseFloat((box_qty * boxWeight).toFixed(3)) } else { grossWeight = 0 }
// 计算净重
netWeight = parseFloat((grossWeight - (box_qty / 2)).toFixed(3))
const newRow = { ...row, _boxKey: newBoxKey, _isFirstRowOfBox: true, _rowSpan: 1, item_no: originalItemNo + index * 0.001, // 使用原序号加小数,保持顺序
box_qty: box_qty, grossWeight: grossWeight, netWeight: netWeight, rolls: rolls, detailRolls: detailRolls // 恢复明细rolls
}
newRows.push(newRow)
// 为新箱保存原始数据(用于后续编辑)
this.mergeBoxOriginalData[newBoxKey] = { box_qty: box_qty, grossWeight: grossWeight, netWeight: netWeight, rolls: rolls, boxWeight: boxWeight } })
// 删除旧的行
selectedBoxKeys.forEach(boxKey => { for (let i = this.mergeBoxTableData.length - 1; i >= 0; i--) { if (this.mergeBoxTableData[i]._boxKey === boxKey) { this.mergeBoxTableData.splice(i, 1) } } })
// 添加新的行
this.mergeBoxTableData.push(...newRows)
// 重新编号
this.renumberBoxes()
// 按序号重新排序表格数据
this.sortTableDataByItemNo()
// 清空选择
this.$refs.mergeBoxTable.clearSelection() this.mergeBoxSelection = []
this.$message.success(`已取消合并,拆分为 ${newRows.length} 个独立的箱,当前共 ${this.getUniqueBoxCount()} 个箱`) },
/** * 重新编号所有箱 */ renumberBoxes() { // 获取所有唯一的箱,并记录每个箱在表格中第一次出现的位置
const boxKeysWithIndex = [] const seenBoxKeys = new Set()
this.mergeBoxTableData.forEach((row, index) => { if (!seenBoxKeys.has(row._boxKey)) { seenBoxKeys.add(row._boxKey) boxKeysWithIndex.push({ boxKey: row._boxKey, item_no: row.item_no, firstIndex: index // 在表格中第一次出现的位置
}) } })
// 按当前序号排序,如果序号相同则按在表格中出现的位置排序
const sortedBoxKeys = boxKeysWithIndex.sort((a, b) => { if (a.item_no !== b.item_no) { return a.item_no - b.item_no } // 序号相同时,按在表格中的位置排序
return a.firstIndex - b.firstIndex })
// 重新分配序号
sortedBoxKeys.forEach((boxInfo, index) => { const newItemNo = index + 1 this.mergeBoxTableData.forEach(row => { if (row._boxKey === boxInfo.boxKey) { row.item_no = newItemNo } }) })
// 更新下一个序号
this.nextItemNo = sortedBoxKeys.length + 1 },
/** * 按序号对表格数据重新排序 */ sortTableDataByItemNo() { this.mergeBoxTableData.sort((a, b) => { // 先按序号排序
if (a.item_no !== b.item_no) { return a.item_no - b.item_no } // 序号相同时,保持原有顺序(同一箱内的明细)
return 0 }) },
/** * 获取唯一箱数量 */ getUniqueBoxCount() { const boxKeys = new Set(this.mergeBoxTableData.map(row => row._boxKey)) return boxKeys.size },
/** * 表格行合并方法 */ mergeBoxSpanMethod({ row, column, rowIndex, columnIndex }) { // Box信息列(前6列:复选框、序号、箱数、毛重、净重、总Rolls)需要合并
if (columnIndex < 6) { if (row._isFirstRowOfBox) { return { rowspan: row._rowSpan, colspan: 1 }; } else { return { rowspan: 0, colspan: 0 }; } } return { rowspan: 1, colspan: 1 }; },
/** * 获取行样式类名 */ getMergeBoxRowClassName({ row }) { const classes = []; // 检查该行是否有Box修改
if (this.mergeBoxModifiedBoxes[row._boxKey]) { classes.push('box-modified-row'); } // 检查该行是否有明细修改
if (row._hasDetail && this.mergeBoxModifiedDetails[row._detailKey]) { classes.push('detail-modified-row'); } return classes.join(' '); },
/** * 检查Box字段是否被修改 */ isBoxFieldModified(row, field) { const boxKey = row._boxKey; return this.mergeBoxModifiedBoxes[boxKey] && this.mergeBoxModifiedBoxes[boxKey][field] !== undefined; },
/** * 检查明细字段是否被修改 */ isDetailFieldModified(row, field) { if (!row._hasDetail) return false; const detailKey = row._detailKey; return this.mergeBoxModifiedDetails[detailKey] && this.mergeBoxModifiedDetails[detailKey][field] !== undefined; },
/** * 箱数输入时联动计算毛重和净重 */ onMergeBoxQtyInput(row) { if (this._isMergeCalculating) return; this._isMergeCalculating = true;
try { const boxKey = row._boxKey; const newBoxQty = parseFloat(row.box_qty) || 0;
// 先从原始数据获取,如果没有则从row缓存获取
let boxWeight = 0; const originalData = this.mergeBoxOriginalData[boxKey]; if (originalData && originalData.boxWeight) { boxWeight = parseFloat(originalData.boxWeight); } else if (row.boxWeightCache) { boxWeight = parseFloat(row.boxWeightCache); }
if (boxWeight > 0 && newBoxQty > 0) { const newGrossWeight = boxWeight * newBoxQty; const newNetWeight = newGrossWeight - (newBoxQty / 2); row.grossWeight = parseFloat(newGrossWeight.toFixed(3)); row.netWeight = parseFloat(newNetWeight.toFixed(3));
// 同步更新所有同Box的行
this.mergeBoxTableData.forEach(r => { if (r._boxKey === boxKey) { r.box_qty = row.box_qty; r.grossWeight = row.grossWeight; r.netWeight = row.netWeight; } });
this.onMergeBoxFieldChange(row, 'grossWeight'); this.onMergeBoxFieldChange(row, 'netWeight'); } } finally { this._isMergeCalculating = false; } },
/** * 毛重输入时联动计算净重 */ onMergeGrossWeightInput(row) { if (this._isMergeCalculating) return; this._isMergeCalculating = true;
try { const grossWeight = parseFloat(row.grossWeight) || 0; const boxQty = parseFloat(row.box_qty) || 0; const netWeight = grossWeight - (boxQty / 2); row.netWeight = netWeight.toFixed(2);
// 同步更新所有同Box的行
const boxKey = row._boxKey; this.mergeBoxTableData.forEach(r => { if (r._boxKey === boxKey) { r.grossWeight = row.grossWeight; r.netWeight = row.netWeight; } });
this.onMergeBoxFieldChange(row, 'netWeight'); } finally { this._isMergeCalculating = false; } },
/** * 净重输入时联动计算毛重 */ onMergeNetWeightInput(row) { if (this._isMergeCalculating) return; this._isMergeCalculating = true;
try { const netWeight = parseFloat(row.netWeight) || 0; const boxQty = parseFloat(row.box_qty) || 0; const grossWeight = netWeight + (boxQty / 2); row.grossWeight = grossWeight.toFixed(2);
// 同步更新所有同Box的行
const boxKey = row._boxKey; this.mergeBoxTableData.forEach(r => { if (r._boxKey === boxKey) { r.netWeight = row.netWeight; r.grossWeight = row.grossWeight; } });
this.onMergeBoxFieldChange(row, 'grossWeight'); } finally { this._isMergeCalculating = false; } },
/** * Box字段变化处理 */ onMergeBoxFieldChange(row, field) { const boxKey = row._boxKey; const original = this.mergeBoxOriginalData[boxKey]; if (!original) return;
const currentValue = String(row[field]); const originalValue = String(original[field]);
if (currentValue !== originalValue) { if (!this.mergeBoxModifiedBoxes[boxKey]) { this.$set(this.mergeBoxModifiedBoxes, boxKey, {}); } this.$set(this.mergeBoxModifiedBoxes[boxKey], field, { oldValue: original[field], newValue: row[field] });
// 同步更新所有同Box的行
this.mergeBoxTableData.forEach(r => { if (r._boxKey === boxKey) { r[field] = row[field]; } }); } else { if (this.mergeBoxModifiedBoxes[boxKey]) { this.$delete(this.mergeBoxModifiedBoxes[boxKey], field); if (Object.keys(this.mergeBoxModifiedBoxes[boxKey]).length === 0) { this.$delete(this.mergeBoxModifiedBoxes, boxKey); } } } },
/** * 明细字段变化处理 */ onMergeDetailFieldChange(row, field) { if (!row._hasDetail) return;
const detailKey = row._detailKey; const original = this.mergeBoxOriginalData[detailKey]; if (!original) return;
const currentValue = String(row[field]); const originalValue = String(original[field]);
if (currentValue !== originalValue) { if (!this.mergeBoxModifiedDetails[detailKey]) { this.$set(this.mergeBoxModifiedDetails, detailKey, { row: row }); } this.$set(this.mergeBoxModifiedDetails[detailKey], field, { oldValue: original[field], newValue: row[field] }); } else { if (this.mergeBoxModifiedDetails[detailKey]) { this.$delete(this.mergeBoxModifiedDetails[detailKey], field); const remainingFields = Object.keys(this.mergeBoxModifiedDetails[detailKey]) .filter(k => k !== 'row'); if (remainingFields.length === 0) { this.$delete(this.mergeBoxModifiedDetails, detailKey); } } } },
/** * 明细Rolls输入事件处理 - 自动计算总Rolls */ onDetailRollsInput(row) { this.$nextTick(() => { this.calculateBoxTotalRolls(row); }); },
/** * 计算同一Box下所有明细Rolls的总和 * 计算规则:总Rolls = Sum(所有明细rolls),然后四舍五入取整 */ calculateBoxTotalRolls(row) { const boxKey = row._boxKey; const boxRows = this.mergeBoxTableData.filter(r => r._boxKey === boxKey && r._hasDetail);
let totalDetailRolls = 0; let hasDetailRolls = false;
boxRows.forEach(r => { const rollsValue = parseFloat(r.detailRolls); if (!isNaN(rollsValue) && rollsValue > 0) { totalDetailRolls += rollsValue; hasDetailRolls = true; } });
// 四舍五入取整(与装箱按钮保持一致)
const newRolls = hasDetailRolls ? Math.round(totalDetailRolls) : 0;
this.mergeBoxTableData.forEach(r => { if (r._boxKey === boxKey) { this.$set(r, 'rolls', newRolls); } });
this.onMergeBoxFieldChange(row, 'rolls'); },
/** * 检查Box是否有明细Rolls值 */ hasDetailRolls(row) { const boxKey = row._boxKey; const boxRows = this.mergeBoxTableData.filter(r => r._boxKey === boxKey && r._hasDetail);
return boxRows.some(r => { const rollsValue = parseFloat(r.detailRolls); return !isNaN(rollsValue) && rollsValue > 0; }); },
/** * 明细数量变化时重新计算rolls */ onDetailQtyChange(row) { // 如果有缓存的每卷数量,重新计算rolls
if (row.rollQtyCache && row.rollQtyCache > 0 && row.qty > 0) { const newRolls = parseFloat((row.qty / row.rollQtyCache).toFixed(4)) this.$set(row, 'detailRolls', newRolls)
// 更新总Rolls
this.$nextTick(() => { this.calculateBoxTotalRolls(row) }) } },
/** * 保存合箱批量编辑 */ async saveMergeBoxEdit() { // 允许直接保存,即使没有修改
this.mergeBoxSaving = true
try { // 构造提交数据 - 按箱分组
const boxMap = new Map()
// 遍历表格数据,按箱分组
this.mergeBoxTableData.forEach(row => { const boxKey = row._boxKey if (!boxMap.has(boxKey)) { boxMap.set(boxKey, { item_no: row.item_no, box_qty: row.box_qty, grossWeight: row.grossWeight, netWeight: row.netWeight, rolls: row.rolls, details: [] }) }
// 添加明细
if (row._hasDetail) { boxMap.get(boxKey).details.push({ itemNo: row.itemNo, poNo: row.poNo, pn: row.pn, qty: row.qty, detailRolls: row.detailRolls, readyDate: row.readyDate }) } })
// 转换为数组
const boxList = Array.from(boxMap.values())
if (boxList.length === 0) { this.$message.warning('没有可保存的箱数据') this.mergeBoxSaving = false return }
const mergeData = { site: this.currentRow.site, buNo: this.currentRow.buNo, delNo: this.currentRow.delNo, createBy: this.$store.state.user.name, boxList: boxList }
// 调用合箱API
const response = await mergeBox(mergeData)
if (response.data && response.data.code === 0) { this.$message.success(`成功保存 ${boxList.length} 个箱的数据`) this.mergeBoxDialogVisible = false // 刷新当前tab表格
this.refreshCurrentTabTable() // 刷新上方的发货通知单列表
this.searchTable() } else { this.$alert(response.data.msg || '保存失败', '错误', { confirmButtonText: '确定' }) } } catch (error) { console.error('保存失败:', error) this.$message.error('保存失败: ' + (error.message || '未知错误')) } finally { this.mergeBoxSaving = false } },
openPalletDialog () { //请求
this.searchPalletList(); }, closePalletDialog () { this.palletList = [] this.palletFlag = false }, searchPalletList () { this.palletData.buNo = this.palletModelData.buNo searchPalletList(this.palletData).then(({data}) => { if (data && data.code === 0){ this.palletList = data.rows; } }) }, palletRowDblclick (row) { this.palletModelData.pallet = row.palletNo this.palletFlag = false },
// 栈板维护相关方法
palletMaintenance() { if(this.currentRow.site===''||this.currentRow.site==null){ this.$alert('请先选择发货通知单!', '错误', { confirmButtonText: '确定' }) return false } // 重置栈板记录
this.palletMaintenanceRecords = [] // 默认根据buNo获取全部栈板
this.loadAllPalletsForMaintenance() this.palletMaintenanceModelFlag = true },
// 根据buNo加载全部栈板用于维护
loadAllPalletsForMaintenance() { let searchData = { palletType: '', // 不限制栈板类型,获取全部
buNo: this.currentRow.buNo } searchPalletList(searchData).then(({data}) => { if (data.code === 0) { const pallets = data.rows || [] // 为每个栈板创建一条记录
this.palletMaintenanceRecords = pallets.map(pallet => ({ pallet: pallet.palletNo, palletType: pallet.palletType, palletQty: '', // 默认为空,用户需要输入
height: '' // 使用栈板的默认高度
})) } }).catch(error => { console.error('加载栈板列表失败:', error) // 如果加载失败,至少添加一行空记录
this.palletMaintenanceRecords = [{ pallet: '', palletType: '', palletQty: '', height: '' }] }) },
savePalletMaintenance() { // 过滤出托数大于0的栈板记录
const validPalletRecords = this.palletMaintenanceRecords.filter(record => { return record.palletQty && parseFloat(record.palletQty) > 0 })
if (validPalletRecords.length === 0) { this.$alert('请至少输入一条有效的栈板记录!', '错误', { confirmButtonText: '确定' }) return false } // 验证有效的栈板记录
for (let i = 0; i < validPalletRecords.length; i++) { const record = validPalletRecords[i] if (!record.pallet) { this.$alert(`栈板不能为空!`, '错误', { confirmButtonText: '确定' }) return false } if (!record.height || record.height <= 0) { this.$alert(`栈板高度必须大于0!`, '错误', { confirmButtonText: '确定' }) return false } } this.saveLoading = true // 这里只新增栈板记录,不做其他事情
let saveData = { site: this.currentRow.site, buNo: this.currentRow.buNo, delNo: this.currentRow.delNo, palletRecords: JSON.stringify(validPalletRecords), }
// 使用相同的API,但传递maintenanceOnly标识
savePalletMaintenance(saveData).then(({data}) => { if (data && data.code === 0) { this.searchTable() this.refreshCurrentTabTable() this.palletMaintenanceModelFlag = false; this.$message({ message: '栈板记录新增成功', type: 'success', duration: 1500, onClose: () => {} }) this.saveLoading = false } else { this.$alert(data.msg, '错误', { confirmButtonText: '确定' }) this.saveLoading = false } }).catch((error) => { console.error('保存失败:', error) this.$message.error('保存失败,请重试') }).finally(() => { this.saveLoading = false }) }, getSummaries(param) { const { columns } = param; const sums = []; columns.forEach((column, index) => { if (index === 0) { sums[index] = '合计'; return; } let sumDataList = this.dataList4.filter(item => item.palletQty>0); const values = sumDataList.map(item => Number(item[column.property])); if (!values.every(value => isNaN(value))) { switch(column.property) { case 'palletQty': sums[index] = `${values.reduce((a, b) => a + b, 0)}`; break; case 'weight': sums[index] = `${values.reduce((a, b) => a + b, 0)}`; break; default: sums[index] = ''; } } else { sums[index] = ''; } }); this.$nextTick(() => this.$refs.detailTable.doLayout());// 强制刷新布局, 否则会被表格覆盖
return sums; }, getDetailSummaries(param) { const { columns } = param; const sums = []; columns.forEach((column, index) => { if (index === 0) { sums[index] = '合计'; return; } let sumDataList = this.dataList2.filter(item => item.qty>0); const values = sumDataList.map(item => Number(item[column.property])); if (!values.every(value => isNaN(value))) { switch(column.property) { case 'qty': sums[index] = `${values.reduce((a, b) => a + b, 0)}`; break; case 'ttlAmount': sums[index] = `${values.reduce((a, b) => a + b, 0).toFixed(2)}`; break; case 'sumPrice': sums[index] = `${values.reduce((a, b) => a + b, 0).toFixed(2)}`; break; default: sums[index] = ''; } } else { sums[index] = ''; } }); this.$nextTick(() => this.$refs.cloDetailTable.doLayout());// 强制刷新布局, 否则会被表格覆盖
return sums; }, /** * 保存选中行到本地存储 * 使用页面路径和用户名作为存储键的一部分,确保不同页面和用户的选择互不影响 */ saveSelectedRowToStorage() { try { const storageKey = `codelnotifyConfirm_selected_row_${this.$store.state.user.name}`; localStorage.setItem(storageKey, this.selectedRowKey); console.log(`[确认页面行选择持久化] 已保存选中行: ${this.selectedRowKey}`); } catch (error) { console.warn('保存选中行状态失败:', error); } },
/** * 从本地存储恢复选中行 * @returns {Object|null} 返回匹配的行数据,如果没有找到则返回null */ restoreSelectedRow() { try { const storageKey = `codelnotifyConfirm_selected_row_${this.$store.state.user.name}`; const savedRowKey = localStorage.getItem(storageKey);
// 检查必要的条件
if (!savedRowKey) { console.log('[确认页面行选择持久化] 没有保存的选中行'); return null; }
if (!this.dataList || this.dataList.length === 0) { console.log('[确认页面行选择持久化] 数据列表为空,无法恢复选中行'); return null; }
// 在当前数据列表中查找匹配的行
const matchedRow = this.dataList.find(row => row && row.delNo === savedRowKey); if (matchedRow) { this.selectedRowKey = savedRowKey; console.log(`[确认页面行选择持久化] 已恢复选中行: ${savedRowKey}`); return matchedRow; } else { console.log(`[确认页面行选择持久化] 未找到匹配的行: ${savedRowKey},当前数据列表长度: ${this.dataList.length}`); }
return null; } catch (error) { console.warn('恢复选中行状态失败:', error); return null; } },
/** * 清除本地存储的选中行状态 */ clearSelectedRowStorage() { try { const storageKey = `codelnotifyConfirm_selected_row_${this.$store.state.user.name}`; localStorage.removeItem(storageKey); this.selectedRowKey = null; } catch (error) { console.warn('清除选中行状态失败:', error); } },
}, activated() { this.searchTable() }, created() { this.getBu () // 动态列
this.getTableUserColumn(this.$route.meta.menuId+'table1',1)
// 初始化时从本地存储加载选中行状态
try { const storageKey = `codelnotifyConfirm_selected_row_${this.$store.state.user.name}`; const savedRowKey = localStorage.getItem(storageKey); if (savedRowKey) { this.selectedRowKey = savedRowKey; } } catch (error) { console.warn('初始化选中行状态失败:', error); } } }</script>
<style lang="scss">.warning-row td{ color: darkred !important;} .zxClass .cell { line-height: 24px; font-size: 12px; height: 24px;}
/* 可点击的PN样式 */.clickable-pn { cursor: pointer; text-decoration: underline;}
.clickable-pn:hover { opacity: 0.8;}
/* 对话框标题样式 */.dialog-title { display: flex; align-items: center; font-size: 16px; font-weight: 500;}
.dialog-title .el-icon-question:hover { color: #66b1ff; transform: scale(1.1); transition: all 0.3s ease;}
/* 表格头部提示图标样式 *//deep/ .el-table th .el-icon-question:hover { color: #409EFF; transform: scale(1.1); transition: all 0.2s ease;}
/* 提示框内容样式 *//deep/ .el-tooltip__popper { max-width: 300px;}
/deep/ .el-tooltip__popper .el-tooltip__content { line-height: 1.6;}
/deep/ .el-tooltip__popper .el-tooltip__content div { margin-bottom: 4px;}
/deep/ .el-tooltip__popper .el-tooltip__content div:first-child { font-weight: bold; margin-bottom: 8px; color: #409EFF;}.pallet-dialog .section { margin: 10px 7px;}
.section-title { font-size: 14px; font-weight: bold; color: #333; margin-bottom: 8px;}
.table-wrapper { height: 300px; /* 让表格部分固定高度并滚动 */ overflow-y: auto;}
/* ========== 合箱批量编辑弹出框样式 ========== */
/* 修复表格滚动条右侧的颜色问题 - 强制设置gutter背景色为白色 */.el-dialog__wrapper .batch-edit-dialog .el-table th.gutter { background-color: #f5f7fa !important;}
/* 工具栏样式 */.merge-box-toolbar { display: flex; align-items: center; margin-bottom: 15px; padding: 10px; background: #f5f7fa; border-radius: 4px;}
.merge-box-toolbar .merge-stats { margin-left: auto; display: flex; align-items: center;}
.merge-box-toolbar .modified-count { color: #e6a23c; margin-left: 10px;}
.merge-box-toolbar .modified-count b { color: #f56c6c; font-size: 16px;}
/* 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+6) { background-color: #fdf6ec !important;}
/deep/ .batch-edit-container .detail-modified-row td:nth-child(n+7) { 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>
|