You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2219 lines
66 KiB

3 months ago
5 months ago
5 months ago
6 months ago
3 months ago
6 months ago
3 months ago
6 months ago
6 months ago
3 months ago
6 months ago
3 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
6 months ago
6 months ago
6 months ago
6 months ago
3 months ago
3 months ago
6 months ago
7 months ago
6 months ago
7 months ago
6 months ago
6 months ago
6 months ago
7 months ago
6 months ago
7 months ago
6 months ago
6 months ago
6 months ago
5 months ago
5 months ago
3 months ago
3 months ago
3 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
3 months ago
5 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
  1. <template>
  2. <div class="packing-detail-tab">
  3. <!-- 批量编辑按钮 -->
  4. <div class="batch-edit-toolbar" v-if="showActions">
  5. <el-button type="primary" size="small" icon="el-icon-edit" @click="openBatchEditDialog">
  6. 批量编辑
  7. </el-button>
  8. <el-button type="warning" size="small" icon="el-icon-s-operation" @click="openAdjustWeightDialog">
  9. 调整总毛重
  10. </el-button>
  11. </div>
  12. <el-table
  13. :data="dataListBoxes"
  14. :height="height"
  15. border
  16. v-loading="dataListLoading"
  17. style="width: 100%;"
  18. :expand-row-keys="expandedBoxRows"
  19. :row-key="getBoxRowKey"
  20. @expand-change="handleBoxExpand"
  21. show-summary
  22. :summary-method="getSummaries">
  23. <el-table-column type="expand" width="70px">
  24. <template slot-scope="props">
  25. <!-- 加载状态 -->
  26. <div v-if="props.row.loading" class="expand-loading">
  27. <i class="el-icon-loading"></i>
  28. <span>正在加载明细数据...</span>
  29. </div>
  30. <!-- 明细内容区域 -->
  31. <div v-else class="expand-detail-container">
  32. <!-- 明细表格 -->
  33. <el-table
  34. v-if="props.row.palletDetails && props.row.palletDetails.length > 0"
  35. :data="props.row.palletDetails"
  36. :max-height="300"
  37. size="mini"
  38. stripe
  39. class="expand-detail-table">
  40. <el-table-column
  41. v-for="(item,index) in columnList3" :key="index"
  42. :sortable="item.columnSortable"
  43. :prop="item.columnProp"
  44. :header-align="item.headerAlign"
  45. :show-overflow-tooltip="item.showOverflowTooltip"
  46. :align="item.align"
  47. :min-width="item.columnWidth"
  48. :label="item.columnLabel">
  49. <template slot-scope="scope">
  50. <span v-if="!item.columnHidden">
  51. {{ formatDetailValue(scope.row[item.columnProp], item.columnProp) }}
  52. </span>
  53. <span v-if="item.columnImage">
  54. <img :src="scope.row[item.columnProp]" style="width: 100px; height: 80px"/>
  55. </span>
  56. </template>
  57. </el-table-column>
  58. <!-- 明细操作列 -->
  59. <el-table-column
  60. label="操作"
  61. width="120"
  62. align="center"
  63. fixed="right">
  64. <template slot-scope="scope">
  65. <a type="text" size="small" v-if="showActions" @click="handleEditDetail(scope.row, props.row)">修改</a>
  66. <a type="text" size="small" v-if="showActions" @click="handleDeleteDetail(scope.row, props.row)">删除</a>
  67. </template>
  68. </el-table-column>
  69. </el-table>
  70. <!-- 空数据状态 -->
  71. <div v-else class="expand-empty-state">
  72. <i class="el-icon-box"></i>
  73. <p>暂无明细数据</p>
  74. <span>该栈板下暂时没有装箱明细信息</span>
  75. </div>
  76. </div>
  77. </template>
  78. </el-table-column>
  79. <el-table-column
  80. v-for="(item,index) in columnListBoxes" :key="index"
  81. :sortable="item.columnSortable"
  82. :prop="item.columnProp"
  83. :header-align="item.headerAlign"
  84. :show-overflow-tooltip="item.showOverflowTooltip"
  85. :align="item.align"
  86. :fixed="item.fixed==''?false:item.fixed"
  87. :min-width="item.columnWidth"
  88. :label="item.columnLabel">
  89. <template slot-scope="scope">
  90. <span v-if="!item.columnHidden"> {{ scope.row[item.columnProp] }}</span>
  91. <span v-if="item.columnImage"><img :src="scope.row[item.columnProp]"
  92. style="width: 100px; height: 80px"/></span>
  93. </template>
  94. </el-table-column>
  95. <!-- 主表格操作列 -->
  96. <el-table-column
  97. label="操作"
  98. width="120"
  99. align="center"
  100. fixed="right">
  101. <template slot-scope="scope">
  102. <a type="text" size="small" v-if="showActions" @click="handleEditBox(scope.row)">修改</a>
  103. <a type="text" size="small" v-if="showActions" @click="handleDeleteBox(scope.row)">删除</a>
  104. </template>
  105. </el-table-column>
  106. </el-table>
  107. <!-- 托盘重量和总毛重显示模拟表格行布局 -->
  108. <div class="weight-summary-table">
  109. <div class="weight-row">
  110. <div class="weight-cell cell-expand label-cell" >托盘重量</div>
  111. <div class="weight-cell cell-data "></div>
  112. <div class="weight-cell cell-data"></div>
  113. <div class="weight-cell cell-data value-cell">{{ palletWeight }}</div>
  114. <div class="weight-cell cell-data"></div>
  115. <div class="weight-cell cell-data"></div>
  116. <div class="weight-cell cell-action"></div>
  117. </div>
  118. <div class="weight-row">
  119. <div class="weight-cell cell-expand label-cell">总毛重</div>
  120. <div class="weight-cell cell-data "></div>
  121. <div class="weight-cell cell-data"></div>
  122. <div class="weight-cell cell-data value-cell">{{ totalGrossWeight.toFixed(2) }}</div>
  123. <div class="weight-cell cell-data"></div>
  124. <div class="weight-cell cell-data"></div>
  125. <div class="weight-cell cell-action"></div>
  126. </div>
  127. </div>
  128. <!-- 修改箱信息弹窗 -->
  129. <el-dialog
  130. title="修改箱信息"
  131. :visible.sync="editBoxDialogVisible"
  132. width="200px"
  133. :close-on-click-modal="false">
  134. <el-form :model="editBoxForm" ref="editBoxForm" label-position="top" label-width="100px">
  135. <el-row :gutter="20">
  136. <el-col :span="12">
  137. <el-form-item label="箱数" prop="box_qty">
  138. <el-input v-model="editBoxForm.box_qty" @input="onBoxQtyChange" :min="1" :precision="0" style="width: 100%"></el-input>
  139. </el-form-item>
  140. </el-col>
  141. <el-col :span="12">
  142. <el-form-item label="毛重" prop="grossWeight">
  143. <el-input v-model="editBoxForm.grossWeight" @input="onGrossWeightChange" :min="0" :precision="2" style="width: 100%"></el-input>
  144. </el-form-item>
  145. </el-col>
  146. <el-col :span="12">
  147. <el-form-item label="净重" prop="netWeight">
  148. <el-input v-model="editBoxForm.netWeight" @input="onNetWeightChange" :min="0" :precision="2" style="width: 100%"></el-input>
  149. </el-form-item>
  150. </el-col>
  151. <el-col :span="12">
  152. <el-form-item label="Rolls" prop="netWeight">
  153. <el-input v-model="editBoxForm.rolls" :min="0" :precision="2" style="width: 100%"></el-input>
  154. </el-form-item>
  155. </el-col>
  156. </el-row>
  157. </el-form>
  158. <div slot="footer" class="dialog-footer">
  159. <el-button @click="editBoxDialogVisible = false">取消</el-button>
  160. <el-button type="primary" @click="submitEditBox" >确定</el-button>
  161. </div>
  162. </el-dialog>
  163. <!-- 修改明细弹窗 -->
  164. <el-dialog
  165. title="修改明细信息"
  166. :visible.sync="editDetailDialogVisible"
  167. width="400px"
  168. :close-on-click-modal="false">
  169. <el-form :model="editDetailForm" ref="editDetailForm" label-position="top" label-width="100px">
  170. <el-row :gutter="20">
  171. <el-col :span="12">
  172. <el-form-item label="PO" prop="poNo">
  173. <el-input v-model="editDetailForm.poNo" disabled></el-input>
  174. </el-form-item>
  175. </el-col>
  176. <el-col :span="12">
  177. <el-form-item label="PN" prop="pn">
  178. <el-input v-model="editDetailForm.pn" disabled></el-input>
  179. </el-form-item>
  180. </el-col>
  181. <el-col :span="12">
  182. <el-form-item label="数量" prop="qty">
  183. <el-input v-model="editDetailForm.qty" style="width: 100%"></el-input>
  184. </el-form-item>
  185. </el-col>
  186. <el-col :span="12">
  187. <el-form-item label="Rolls" prop="rolls">
  188. <el-input v-model="editDetailForm.rolls" style="width: 100%"></el-input>
  189. </el-form-item>
  190. </el-col>
  191. </el-row>
  192. </el-form>
  193. <div slot="footer" class="dialog-footer">
  194. <el-button @click="editDetailDialogVisible = false">取消</el-button>
  195. <el-button type="primary" @click="submitEditDetail" >确定</el-button>
  196. </div>
  197. </el-dialog>
  198. <!-- 批量编辑弹窗 -->
  199. <el-dialog
  200. title="批量编辑装箱明细"
  201. :visible.sync="batchEditDialogVisible"
  202. width="60%"
  203. top="5vh"
  204. custom-class="batch-edit-dialog"
  205. :close-on-click-modal="false"
  206. @open="loadBatchEditData">
  207. <div class="batch-edit-container" v-loading="batchEditLoading">
  208. <!-- 操作提示 -->
  209. <div class="batch-edit-tips">
  210. <el-alert
  211. type="info"
  212. :closable="false"
  213. show-icon>
  214. <template slot="title">
  215. <span>直接在表格中编辑数据修改后点击"保存所有修改"按钮提交</span>
  216. <span v-if="batchEditModifiedCount > 0" class="modified-count">
  217. 已修改 <b>{{ batchEditModifiedCount }}</b>
  218. </span>
  219. </template>
  220. </el-alert>
  221. </div>
  222. <!-- 行合并表格 -->
  223. <el-table
  224. :data="batchEditTableData"
  225. :span-method="batchEditSpanMethod"
  226. border
  227. size="small"
  228. max-height="60vh"
  229. style="width: 100%"
  230. :row-class-name="getBatchEditRowClassName"
  231. :header-cell-style="{background:'#f5f7fa', color:'#606266', fontWeight:'600'}">
  232. <!-- Box信息列会合并 -->
  233. <el-table-column label="序号" prop="item_no" width="60" align="center">
  234. <template slot-scope="scope">
  235. <span class="box-info-cell">{{ scope.row.item_no }}</span>
  236. </template>
  237. </el-table-column>
  238. <el-table-column label="箱数" prop="box_qty" width="80" align="center">
  239. <template slot-scope="scope">
  240. <el-input
  241. v-model="scope.row.box_qty"
  242. size="mini"
  243. type="number"
  244. :class="{'modified-input': isBoxFieldModified(scope.row, 'box_qty')}"
  245. @input="onBatchBoxQtyInput(scope.row)"
  246. @change="onBatchBoxFieldChange(scope.row, 'box_qty')">
  247. </el-input>
  248. </template>
  249. </el-table-column>
  250. <el-table-column label="毛重" prop="grossWeight" width="100" align="center">
  251. <template slot-scope="scope">
  252. <el-input
  253. v-model="scope.row.grossWeight"
  254. size="mini"
  255. type="number"
  256. :class="{'modified-input': isBoxFieldModified(scope.row, 'grossWeight')}"
  257. @input="onBatchGrossWeightInput(scope.row)"
  258. @change="onBatchBoxFieldChange(scope.row, 'grossWeight')">
  259. </el-input>
  260. </template>
  261. </el-table-column>
  262. <el-table-column label="净重" prop="netWeight" width="100" align="center">
  263. <template slot-scope="scope">
  264. <el-input
  265. v-model="scope.row.netWeight"
  266. size="mini"
  267. type="number"
  268. :class="{'modified-input': isBoxFieldModified(scope.row, 'netWeight')}"
  269. @input="onBatchNetWeightInput(scope.row)"
  270. @change="onBatchBoxFieldChange(scope.row, 'netWeight')">
  271. </el-input>
  272. </template>
  273. </el-table-column>
  274. <el-table-column label="总Rolls" prop="rolls" width="100" align="center">
  275. <template slot-scope="scope">
  276. <el-input
  277. v-model="scope.row.rolls"
  278. size="mini"
  279. type="number"
  280. :disabled="hasDetailRolls(scope.row)"
  281. :placeholder="hasDetailRolls(scope.row) ? '自动计算' : '请输入'"
  282. :class="{'modified-input': isBoxFieldModified(scope.row, 'rolls')}"
  283. @change="onBatchBoxFieldChange(scope.row, 'rolls')">
  284. </el-input>
  285. </template>
  286. </el-table-column>
  287. <!-- 明细信息列不合并 -->
  288. <el-table-column label="PO" prop="poNo" min-width="120" align="left">
  289. <template slot-scope="scope">
  290. <span>{{ scope.row.poNo || '-' }}</span>
  291. </template>
  292. </el-table-column>
  293. <el-table-column label="PN" prop="pn" min-width="120" align="left">
  294. <template slot-scope="scope">
  295. <span>{{ scope.row.pn || '-' }}</span>
  296. </template>
  297. </el-table-column>
  298. <el-table-column label="数量" prop="qty" width="100" align="center">
  299. <template slot-scope="scope">
  300. <el-input
  301. v-model="scope.row.qty"
  302. size="mini"
  303. type="number"
  304. :class="{'modified-input': isDetailFieldModified(scope.row, 'qty')}"
  305. @change="onBatchDetailFieldChange(scope.row, 'qty')">
  306. </el-input>
  307. </template>
  308. </el-table-column>
  309. <el-table-column label="Rolls" prop="detailRolls" width="80" align="center">
  310. <template slot-scope="scope">
  311. <el-input
  312. v-model="scope.row.detailRolls"
  313. size="mini"
  314. type="number"
  315. :class="{'modified-input': isDetailFieldModified(scope.row, 'detailRolls')}"
  316. @input="onDetailRollsInput(scope.row)"
  317. @change="onBatchDetailFieldChange(scope.row, 'detailRolls')">
  318. </el-input>
  319. </template>
  320. </el-table-column>
  321. </el-table>
  322. </div>
  323. <div slot="footer" class="dialog-footer">
  324. <el-button @click="batchEditDialogVisible = false">取消</el-button>
  325. <el-button
  326. type="primary"
  327. :loading="batchEditSaving"
  328. :disabled="batchEditModifiedCount === 0"
  329. @click="saveBatchEdit">
  330. 保存所有修改 ({{ batchEditModifiedCount }})
  331. </el-button>
  332. </div>
  333. </el-dialog>
  334. <!-- 调整总毛重弹窗 -->
  335. <el-dialog
  336. title="调整实际总毛重"
  337. :visible.sync="adjustWeightDialogVisible"
  338. width="450px"
  339. :close-on-click-modal="false">
  340. <el-form :model="adjustWeightForm" label-width="250px">
  341. <!-- 当前重量信息 -->
  342. <el-form-item label="当前总毛重:">
  343. <span class="weight-display">{{ currentTotalGrossWeight.toFixed(3) }} KG</span>
  344. </el-form-item>
  345. <el-form-item label="托盘重量:">
  346. <span class="weight-display-small">{{ palletWeight.toFixed(3) }} KG</span>
  347. </el-form-item>
  348. <el-divider></el-divider>
  349. <!-- 输入框 - 最突出 -->
  350. <el-form-item label="实际总毛重(不包含托盘重量):" required class="input-highlight">
  351. <el-input
  352. ref="actualWeightInput"
  353. v-model="adjustWeightForm.actualGrossWeight"
  354. placeholder="请输入实际称重的总毛重(KG)"
  355. @keyup.enter.native="submitAdjustWeight()"
  356. size="large"
  357. clearable
  358. autofocus>
  359. </el-input>
  360. <div style="font-size: 12px; color: #909399; margin-top: 5px; line-height: 1.5;">
  361. 输入的总毛重不含托盘重量
  362. </div>
  363. </el-form-item>
  364. <!-- 说明 -->
  365. <el-alert
  366. title="系统将按原箱毛重比例重新分配各箱毛重,并自动重新计算净重"
  367. type="info"
  368. :closable="false"
  369. show-icon>
  370. </el-alert>
  371. </el-form>
  372. <div slot="footer" class="dialog-footer">
  373. <el-button @click="adjustWeightDialogVisible = false">取消</el-button>
  374. <el-button
  375. type="primary"
  376. :loading="adjustWeightSaving"
  377. @click="submitAdjustWeight">
  378. 确定调整
  379. </el-button>
  380. </div>
  381. </el-dialog>
  382. </div>
  383. </template>
  384. <script>
  385. import { selectBoxList, searchCoDelPalletDataNew, updateBoxInfo, deleteBoxInfo, updateDetailInfo, deleteDetailInfo, batchUpdatePackingInfo, searchEcssCoDelPalletHeaderData, adjustTotalGrossWeight } from "@/api/ecss/ecss.js"
  386. export default {
  387. name: "PackingDetailTab",
  388. props: {
  389. currentRow: {
  390. type: Object,
  391. default: () => ({})
  392. },
  393. height: {
  394. type: Number,
  395. default: 200
  396. },
  397. showActions: {
  398. type: Boolean,
  399. default: true
  400. }
  401. },
  402. data() {
  403. return {
  404. dataListBoxes: [], // 箱数据列表
  405. expandedBoxRows: [], // 展开的行
  406. dataListLoading: false,
  407. // 托盘重量相关
  408. palletWeight: 0, // 托盘重量合计
  409. totalGrossWeight: 0, // 总毛重(合计毛重 + 托盘重量)
  410. // 修改箱信息弹窗相关
  411. editBoxDialogVisible: false,
  412. editBoxForm: {
  413. item_no: '',
  414. box_qty: 1,
  415. grossWeight: 0,
  416. netWeight: 0,
  417. rolls: 0,
  418. boxWeight: 0 // 物料的箱重量(BOXWEIGHT)
  419. },
  420. editBoxSubmitting: false,
  421. currentEditBox: null,
  422. // 修改明细弹窗相关
  423. editDetailDialogVisible: false,
  424. editDetailForm: {
  425. itemNo: '',
  426. poNo: '',
  427. pn: '',
  428. qty: 1,
  429. rolls: 0
  430. },
  431. editDetailSubmitting: false,
  432. currentEditDetail: null,
  433. currentEditBoxForDetail: null,
  434. // 批量编辑弹窗相关
  435. batchEditDialogVisible: false,
  436. batchEditLoading: false,
  437. batchEditSaving: false,
  438. batchEditTableData: [], // 扁平化的表格数据
  439. batchEditOriginalData: {}, // 原始数据快照(用于对比是否修改)
  440. batchEditModifiedBoxes: {}, // 修改过的Box记录
  441. batchEditModifiedDetails: {}, // 修改过的明细记录
  442. batchEditSpanInfo: [], // 行合并信息
  443. // 调整总毛重弹窗相关
  444. adjustWeightDialogVisible: false,
  445. adjustWeightSaving: false,
  446. adjustWeightForm: {
  447. actualGrossWeight: ''
  448. },
  449. // 装箱明细列定义
  450. columnList3: [
  451. {
  452. userId: this.$store.state.user.name,
  453. functionId: 801002,
  454. serialNumber: '801002Table3ItemNo',
  455. tableId: "801002Table3",
  456. tableName: "装箱明细",
  457. columnProp: "itemNo",
  458. headerAlign: "center",
  459. align: "right",
  460. columnLabel: "序号",
  461. columnHidden: false,
  462. columnImage: false,
  463. columnSortable: false,
  464. sortLv: 0,
  465. status: true,
  466. fixed: '',
  467. columnWidth: 100
  468. },
  469. {
  470. userId: this.$store.state.user.name,
  471. functionId: 801002,
  472. serialNumber: '801002Table3PoNo',
  473. tableId: "801002Table3",
  474. tableName: "装箱明细",
  475. columnProp: "poNo",
  476. headerAlign: "center",
  477. align: "left",
  478. columnLabel: "PO",
  479. columnHidden: false,
  480. columnImage: false,
  481. columnSortable: false,
  482. sortLv: 0,
  483. status: true,
  484. fixed: '',
  485. columnWidth: 100
  486. },
  487. {
  488. userId: this.$store.state.user.name,
  489. functionId: 801002,
  490. serialNumber: '801002Table3PN',
  491. tableId: "801002Table3",
  492. tableName: "装箱明细",
  493. columnProp: "pn",
  494. headerAlign: "center",
  495. align: "left",
  496. columnLabel: "PN",
  497. columnHidden: false,
  498. columnImage: false,
  499. columnSortable: false,
  500. sortLv: 0,
  501. status: true,
  502. fixed: '',
  503. columnWidth: 100
  504. },
  505. {
  506. userId: this.$store.state.user.name,
  507. functionId: 801002,
  508. serialNumber: '801002Table3Qty',
  509. tableId: "801002Table3",
  510. tableName: "装箱明细",
  511. columnProp: "qty",
  512. headerAlign: "center",
  513. align: "right",
  514. columnLabel: "数量",
  515. columnHidden: false,
  516. columnImage: false,
  517. columnSortable: false,
  518. sortLv: 0,
  519. status: true,
  520. fixed: '',
  521. columnWidth: 50
  522. },
  523. {
  524. userId: this.$store.state.user.name,
  525. functionId: 801002,
  526. serialNumber: '801002Table3Rolls',
  527. tableId: "801002Table3",
  528. tableName: "装箱明细",
  529. columnProp: "rolls",
  530. headerAlign: "center",
  531. align: "right",
  532. columnLabel: "Rolls",
  533. columnHidden: false,
  534. columnImage: false,
  535. columnSortable: false,
  536. sortLv: 0,
  537. status: true,
  538. fixed: '',
  539. columnWidth: 50
  540. },
  541. ],
  542. // 箱数据列定义
  543. columnListBoxes: [
  544. {
  545. userId: this.$store.state.user.name,
  546. functionId: 801002,
  547. serialNumber: '801002Table3ItemNo',
  548. tableId: "801002Table3",
  549. tableName: "装箱明细",
  550. columnProp: "item_no",
  551. headerAlign: "center",
  552. align: "right",
  553. columnLabel: "序号",
  554. columnHidden: false,
  555. columnImage: false,
  556. columnSortable: false,
  557. sortLv: 0,
  558. status: true,
  559. fixed: '',
  560. columnWidth: 50
  561. },
  562. {
  563. userId: this.$store.state.user.name,
  564. functionId: 801002,
  565. serialNumber: '801002Table3BoxQty',
  566. tableId: "801002Table3",
  567. tableName: "装箱明细",
  568. columnProp: "box_qty",
  569. headerAlign: "center",
  570. align: "right",
  571. columnLabel: "箱数",
  572. columnHidden: false,
  573. columnImage: false,
  574. columnSortable: false,
  575. sortLv: 0,
  576. status: true,
  577. fixed: '',
  578. columnWidth: 50
  579. },
  580. {
  581. userId: this.$store.state.user.name,
  582. functionId: 801002,
  583. serialNumber: '801002TableGrossWeight',
  584. tableId: "801002Table3",
  585. tableName: "装箱明细",
  586. columnProp: "grossWeight",
  587. headerAlign: "center",
  588. align: "right",
  589. columnLabel: "毛重",
  590. columnHidden: false,
  591. columnImage: false,
  592. columnSortable: false,
  593. sortLv: 0,
  594. status: true,
  595. fixed: '',
  596. columnWidth: 50
  597. },
  598. {
  599. userId: this.$store.state.user.name,
  600. functionId: 801002,
  601. serialNumber: '801002TableNetWeight',
  602. tableId: "801002Table3",
  603. tableName: "装箱明细",
  604. columnProp: "netWeight",
  605. headerAlign: "center",
  606. align: "right",
  607. columnLabel: "净重",
  608. columnHidden: false,
  609. columnImage: false,
  610. columnSortable: false,
  611. sortLv: 0,
  612. status: true,
  613. fixed: '',
  614. columnWidth: 50
  615. },
  616. {
  617. userId: this.$store.state.user.name,
  618. functionId: 801002,
  619. serialNumber: '801002TableNetWeight',
  620. tableId: "801002Table3",
  621. tableName: "装箱明细",
  622. columnProp: "rolls",
  623. headerAlign: "center",
  624. align: "right",
  625. columnLabel: "总Rolls",
  626. columnHidden: false,
  627. columnImage: false,
  628. columnSortable: false,
  629. sortLv: 0,
  630. status: true,
  631. fixed: '',
  632. columnWidth: 50
  633. },
  634. ]
  635. }
  636. },
  637. computed: {
  638. // 批量编辑修改数量
  639. batchEditModifiedCount() {
  640. return Object.keys(this.batchEditModifiedBoxes).length +
  641. Object.keys(this.batchEditModifiedDetails).length;
  642. },
  643. // 当前合计毛重(不含托盘)
  644. currentTotalGrossWeight() {
  645. return this.dataListBoxes.reduce((sum, item) => {
  646. return sum + (Number(item.grossWeight) || 0);
  647. }, 0);
  648. }
  649. },
  650. watch: {
  651. currentRow: {
  652. handler(newVal) {
  653. if (newVal && newVal.site) {
  654. this.loadBoxList();
  655. }
  656. },
  657. deep: true,
  658. immediate: true
  659. }
  660. },
  661. methods: {
  662. // 装箱明细相关方法
  663. loadBoxList() {
  664. if (!this.currentRow || !this.currentRow.site) {
  665. this.dataListBoxes = [];
  666. this.palletWeight = 0;
  667. this.totalGrossWeight = 0;
  668. return;
  669. }
  670. // 清理之前的展开状态
  671. this.expandedBoxRows = [];
  672. this.dataListLoading = true;
  673. // 同时获取箱数据和托盘数据
  674. Promise.all([
  675. selectBoxList(this.currentRow),
  676. searchEcssCoDelPalletHeaderData(this.currentRow)
  677. ]).then(([boxResponse, palletResponse]) => {
  678. // 处理箱数据
  679. if (boxResponse.data && boxResponse.data.code == 0) {
  680. this.dataListBoxes = boxResponse.data.rows.map(row => ({
  681. ...row,
  682. palletDetails: [], // 初始化明细数据为空
  683. loading: false, // 初始化加载状态
  684. hadDetails: false // 初始化是否有明细标记
  685. }));
  686. } else {
  687. this.dataListBoxes = [];
  688. }
  689. // 处理托盘数据 - 计算托盘重量合计
  690. if (palletResponse.data && palletResponse.data.code == 0) {
  691. const palletList = palletResponse.data.rows || [];
  692. // 只统计 palletQty > 0 的托盘重量
  693. this.palletWeight = palletList
  694. .filter(item => item.palletQty > 0)
  695. .reduce((sum, item) => sum + (Number(item.weight) || 0), 0);
  696. } else {
  697. this.palletWeight = 0;
  698. }
  699. // 计算总毛重 = 合计毛重 + 托盘重量
  700. this.calculateTotalGrossWeight();
  701. }).catch(error => {
  702. console.error('加载数据失败:', error);
  703. this.dataListBoxes = [];
  704. this.palletWeight = 0;
  705. this.totalGrossWeight = 0;
  706. }).finally(() => {
  707. this.dataListLoading = false;
  708. });
  709. },
  710. // 计算总毛重
  711. calculateTotalGrossWeight() {
  712. const boxGrossWeight = this.dataListBoxes.reduce((sum, item) => {
  713. return sum + (Number(item.grossWeight) || 0);
  714. }, 0);
  715. this.totalGrossWeight = boxGrossWeight + this.palletWeight;
  716. },
  717. // 获取行的唯一标识
  718. getBoxRowKey(row) {
  719. // 使用多个字段组合确保唯一性
  720. return `${row.item_no || ''}_${row.palletRemark || ''}_${row.box_qty || ''}`;
  721. },
  722. // 处理行展开事件
  723. handleBoxExpand(row, expandedRows) {
  724. // 判断当前操作是展开还是收起
  725. const isExpanding = expandedRows.includes(row);
  726. if (isExpanding) {
  727. // 如果是展开操作,则展开所有行
  728. this.expandAll();
  729. } else {
  730. // 如果是收起操作,则收起所有行
  731. this.collapseAll();
  732. }
  733. },
  734. // 加载栈板明细数据
  735. loadPalletDetails(boxRow) {
  736. if (boxRow.palletDetails && boxRow.palletDetails.length > 0) {
  737. // 如果已经加载过,直接返回
  738. return;
  739. }
  740. // 设置加载状态
  741. this.$set(boxRow, 'loading', true);
  742. // 构造查询参数
  743. let detailParams = {
  744. site: this.currentRow.site,
  745. buNo: this.currentRow.buNo,
  746. delNo: this.currentRow.delNo,
  747. seqNo: boxRow.item_no,
  748. palletRemark: boxRow.palletRemark
  749. };
  750. // 调用API获取明细数据
  751. searchCoDelPalletDataNew(detailParams).then(({data}) => {
  752. if (data && data.code == 0) {
  753. // 将明细数据赋值给当前行
  754. this.$set(boxRow, 'palletDetails', data.rows);
  755. // 如果明细为空,且之前有明细数据,说明明细被删除了,需要检查box是否也应该被删除
  756. if (data.rows.length === 0 && boxRow.hadDetails) {
  757. // 延迟刷新列表,让后端有时间处理删除逻辑
  758. setTimeout(() => {
  759. this.loadBoxList();
  760. }, 500);
  761. }
  762. // 标记是否有过明细数据
  763. this.$set(boxRow, 'hadDetails', data.rows.length > 0);
  764. } else {
  765. this.$set(boxRow, 'palletDetails', []);
  766. this.$set(boxRow, 'hadDetails', false);
  767. }
  768. }).catch(error => {
  769. console.error('加载栈板明细数据失败:', error);
  770. this.$set(boxRow, 'palletDetails', []);
  771. this.$set(boxRow, 'hadDetails', false);
  772. }).finally(() => {
  773. // 清除加载状态
  774. this.$set(boxRow, 'loading', false);
  775. });
  776. },
  777. // 格式化明细值显示
  778. formatDetailValue(value, columnProp) {
  779. if (value === null || value === undefined || value === '') {
  780. return '-';
  781. }
  782. // 数字类型格式化
  783. if (columnProp === 'qty' || columnProp === 'rolls') {
  784. return parseInt(value).toLocaleString();
  785. }
  786. return value;
  787. },
  788. // 展开所有行
  789. expandAll() {
  790. // 获取所有行的key
  791. this.expandedBoxRows = this.dataListBoxes.map(row => this.getBoxRowKey(row));
  792. // 为每个行加载明细数据
  793. this.dataListBoxes.forEach(row => {
  794. this.loadPalletDetails(row);
  795. });
  796. },
  797. // 收起所有行
  798. collapseAll() {
  799. this.expandedBoxRows = [];
  800. },
  801. // 刷新数据的公共方法
  802. refresh() {
  803. this.loadBoxList();
  804. },
  805. /*
  806. * 删除逻辑说明
  807. * 1. 删除明细时
  808. * - 先删除明细数据
  809. * - 检查该明细所属的box是否还有其他明细
  810. * - 如果没有明细了自动删除对应的box
  811. *
  812. * 2. 删除box时
  813. * - 先检查是否有明细数据
  814. * - 如果有明细提示用户并同时删除所有明细和box
  815. * - 如果没有明细直接删除box
  816. */
  817. // 处理修改箱信息
  818. handleEditBox(boxRow) {
  819. this.currentEditBox = boxRow;
  820. this.editBoxForm.item_no = boxRow.item_no;
  821. this.editBoxForm.box_qty = boxRow.box_qty;
  822. this.editBoxForm.grossWeight = boxRow.grossWeight;
  823. this.editBoxForm.netWeight = boxRow.netWeight;
  824. this.editBoxForm.rolls = boxRow.rolls;
  825. this.editBoxForm.boxWeight = boxRow.boxWeight || 0; // 保存物料的箱重量
  826. this.editBoxDialogVisible = true;
  827. },
  828. // 处理删除箱信息
  829. handleDeleteBox(boxRow) {
  830. // 直接删除box及其所有明细,无需校验
  831. this.deleteBoxWithDetails(boxRow);
  832. },
  833. // 删除箱信息(包含明细)
  834. deleteBoxWithDetails(boxRow) {
  835. this.$confirm(`确定要删除序号为 ${boxRow.item_no} 的箱信息吗?删除后无法恢复!`, '警告', {
  836. confirmButtonText: '确定',
  837. cancelButtonText: '取消',
  838. type: 'warning'
  839. }).then(() => {
  840. // 构造删除参数
  841. const deleteParams = {
  842. site: this.currentRow.site,
  843. buNo: this.currentRow.buNo,
  844. delNo: this.currentRow.delNo,
  845. item_no: boxRow.item_no,
  846. palletRemark: boxRow.palletRemark
  847. };
  848. deleteBoxInfo(deleteParams).then(({data}) => {
  849. if (data && data.code === 0) {
  850. this.loadBoxList()
  851. this.$emit('refresh') // 刷新父页面列表
  852. this.$message({
  853. message: '操作成功',
  854. type: 'success',
  855. duration: 1500,
  856. onClose: () => {}
  857. })
  858. } else {
  859. this.$alert(data.msg, '错误', {
  860. confirmButtonText: '确定'
  861. })
  862. }
  863. })
  864. });
  865. },
  866. // 处理修改明细
  867. handleEditDetail(detailRow, boxRow) {
  868. this.currentEditDetail = detailRow;
  869. this.currentEditBoxForDetail = boxRow;
  870. this.editDetailForm.itemNo = detailRow.itemNo;
  871. this.editDetailForm.poNo = detailRow.poNo;
  872. this.editDetailForm.pn = detailRow.pn;
  873. this.editDetailForm.qty = detailRow.qty;
  874. this.editDetailForm.rolls = detailRow.rolls;
  875. this.editDetailDialogVisible = true;
  876. },
  877. /**
  878. * 箱数改变时自动计算毛重和净重
  879. * 计算公式
  880. * 1. 新毛重 = 物料箱重量(BOXWEIGHT) × 新箱数
  881. * 2. 新净重 = 新毛重 - box_qty/2
  882. */
  883. onBoxQtyChange(value) {
  884. // 防止循环触发,使用标志位
  885. if (this._isCalculating) {
  886. return;
  887. }
  888. this._isCalculating = true;
  889. try {
  890. const newBoxQty = parseFloat(value) || 0;
  891. const boxWeight = parseFloat(this.editBoxForm.boxWeight) || 0;
  892. if (boxWeight <= 0) {
  893. this.$message.warning('该物料未配置箱重量,无法自动计算毛重');
  894. this._isCalculating = false;
  895. return;
  896. }
  897. // 根据物料箱重量计算新毛重:新毛重 = 箱重量 × 箱数
  898. const newGrossWeight = boxWeight * newBoxQty;
  899. // 计算新净重:净重 = 毛重 - box_qty/2
  900. const newNetWeight = newGrossWeight - (newBoxQty / 2);
  901. // 保留3位小数
  902. this.editBoxForm.grossWeight = newGrossWeight.toFixed(3);
  903. this.editBoxForm.netWeight = newNetWeight.toFixed(3);
  904. } finally {
  905. this._isCalculating = false;
  906. }
  907. },
  908. /**
  909. * 毛重改变时自动计算净重
  910. * 计算公式净重 = 毛重 - box_qty/2
  911. */
  912. onGrossWeightChange(value) {
  913. // 防止循环触发,使用标志位
  914. if (this._isCalculating) {
  915. return;
  916. }
  917. this._isCalculating = true;
  918. try {
  919. const grossWeight = parseFloat(value) || 0;
  920. const boxQty = parseFloat(this.editBoxForm.box_qty) || 0;
  921. // 计算净重:净重 = 毛重 - box_qty/2
  922. const netWeight = grossWeight - (boxQty / 2);
  923. // 保留2位小数
  924. this.editBoxForm.netWeight = netWeight.toFixed(2);
  925. } finally {
  926. this._isCalculating = false;
  927. }
  928. },
  929. /**
  930. * 净重改变时自动计算毛重
  931. * 反向计算公式毛重 = 净重 + box_qty/2
  932. */
  933. onNetWeightChange(value) {
  934. // 防止循环触发,使用标志位
  935. if (this._isCalculating) {
  936. return;
  937. }
  938. this._isCalculating = true;
  939. try {
  940. const netWeight = parseFloat(value) || 0;
  941. const boxQty = parseFloat(this.editBoxForm.box_qty) || 0;
  942. // 反向计算毛重:毛重 = 净重 + box_qty/2
  943. const grossWeight = netWeight + (boxQty / 2);
  944. // 保留2位小数
  945. this.editBoxForm.grossWeight = grossWeight.toFixed(2);
  946. } finally {
  947. this._isCalculating = false;
  948. }
  949. },
  950. // 提交修改箱信息
  951. submitEditBox() {
  952. this.$refs.editBoxForm.validate(valid => {
  953. if (valid) {
  954. this.editBoxSubmitting = true;
  955. // 构造更新参数
  956. const updateParams = {
  957. site: this.currentRow.site,
  958. buNo: this.currentRow.buNo,
  959. delNo: this.currentRow.delNo,
  960. item_no: this.currentEditBox.item_no,
  961. palletRemark: this.currentEditBox.palletRemark,
  962. box_qty: this.editBoxForm.box_qty,
  963. grossWeight: this.editBoxForm.grossWeight,
  964. netWeight: this.editBoxForm.netWeight,
  965. rolls: this.editBoxForm.rolls,
  966. updateBy: this.$store.state.user.name
  967. };
  968. updateBoxInfo(updateParams).then(({ data }) => {
  969. if (data && data.code === 0) {
  970. this.editBoxDialogVisible = false;
  971. this.loadBoxList()
  972. this.$emit('refresh') // 刷新父页面列表
  973. this.$message({
  974. message: '操作成功',
  975. type: 'success',
  976. duration: 1500,
  977. onClose: () => {}
  978. })
  979. } else {
  980. this.$alert(data.msg, '错误', {
  981. confirmButtonText: '确定'
  982. })
  983. }
  984. });
  985. }
  986. });
  987. },
  988. // 提交修改明细
  989. submitEditDetail() {
  990. this.$refs.editDetailForm.validate(valid => {
  991. if (valid) {
  992. this.editDetailSubmitting = true;
  993. // 构造更新参数
  994. const updateParams = {
  995. site: this.currentRow.site,
  996. buNo: this.currentRow.buNo,
  997. delNo: this.currentRow.delNo,
  998. seqNo: this.currentEditDetail.seqNo,
  999. itemNo: this.currentEditDetail.itemNo,
  1000. notifyDetailItemNo: this.currentEditDetail.notifyDetailItemNo,
  1001. poNo: this.editDetailForm.poNo,
  1002. pn: this.editDetailForm.pn,
  1003. qty: this.editDetailForm.qty,
  1004. oldQty: this.currentEditDetail.qty,
  1005. rolls: this.editDetailForm.rolls,
  1006. updateBy: this.$store.state.user.name
  1007. };
  1008. updateDetailInfo(updateParams).then(({ data }) => {
  1009. if (data && data.code === 0) {
  1010. this.editDetailDialogVisible = false;
  1011. this.loadBoxList()
  1012. this.$emit('refresh') // 刷新父页面列表
  1013. this.$message({
  1014. message: '操作成功',
  1015. type: 'success',
  1016. duration: 1500,
  1017. onClose: () => {}
  1018. })
  1019. } else {
  1020. this.$alert(data.msg, '错误', {
  1021. confirmButtonText: '确定'
  1022. })
  1023. }
  1024. });
  1025. }
  1026. });
  1027. },
  1028. // 删除明细
  1029. handleDeleteDetail(detailRow, boxRow) {
  1030. this.$confirm(`确定要删除这个明细信息吗?删除后无法恢复!`, '警告', {
  1031. confirmButtonText: '确定',
  1032. cancelButtonText: '取消',
  1033. type: 'warning'
  1034. }).then(() => {
  1035. // 构造删除参数
  1036. const deleteParams = {
  1037. site: this.currentRow.site,
  1038. buNo: this.currentRow.buNo,
  1039. delNo: this.currentRow.delNo,
  1040. seqNo: detailRow.seqNo,
  1041. itemNo: detailRow.itemNo,
  1042. notifyDetailItemNo: detailRow.notifyDetailItemNo,
  1043. partNo: detailRow.part_no,
  1044. qty: detailRow.qty
  1045. };
  1046. deleteDetailInfo(deleteParams).then(({data}) => {
  1047. if (data && data.code === 0) {
  1048. this.loadBoxList()
  1049. this.$emit('refresh') // 刷新父页面列表
  1050. this.$message({
  1051. message: '操作成功',
  1052. type: 'success',
  1053. duration: 1500,
  1054. onClose: () => {}
  1055. })
  1056. } else {
  1057. this.$alert(data.msg, '错误', {
  1058. confirmButtonText: '确定'
  1059. })
  1060. }
  1061. })
  1062. });
  1063. },
  1064. // 计算合计行数据
  1065. getSummaries(param) {
  1066. const { columns, data } = param;
  1067. const sums = [];
  1068. columns.forEach((column, index) => {
  1069. if (index === 0) {
  1070. // 第一列(展开列)显示"合计"
  1071. sums[index] = '合计';
  1072. return;
  1073. }
  1074. const values = data.map(item => Number(item[column.property]));
  1075. // 根据列属性计算合计
  1076. if (column.property === 'box_qty') {
  1077. // 箱数合计
  1078. const sum = values.reduce((prev, curr) => {
  1079. const value = Number(curr);
  1080. if (!isNaN(value)) {
  1081. return prev + value;
  1082. } else {
  1083. return prev;
  1084. }
  1085. }, 0);
  1086. sums[index] = sum;
  1087. } else if (column.property === 'grossWeight') {
  1088. // 毛重合计
  1089. const sum = values.reduce((prev, curr) => {
  1090. const value = Number(curr);
  1091. if (!isNaN(value)) {
  1092. return prev + value;
  1093. } else {
  1094. return prev;
  1095. }
  1096. }, 0);
  1097. sums[index] = sum.toFixed(3);
  1098. } else if (column.property === 'netWeight') {
  1099. // 净重合计
  1100. const sum = values.reduce((prev, curr) => {
  1101. const value = Number(curr);
  1102. if (!isNaN(value)) {
  1103. return prev + value;
  1104. } else {
  1105. return prev;
  1106. }
  1107. }, 0);
  1108. sums[index] = sum.toFixed(3);
  1109. } else if (column.property === 'rolls') {
  1110. // 净重合计
  1111. const sum = values.reduce((prev, curr) => {
  1112. const value = Number(curr);
  1113. if (!isNaN(value)) {
  1114. return prev + value;
  1115. } else {
  1116. return prev;
  1117. }
  1118. }, 0);
  1119. sums[index] = sum.toFixed(3);
  1120. } else if (column.property === 'item_no') {
  1121. // 序号列显示空
  1122. sums[index] = '';
  1123. } else {
  1124. // 其他列显示空
  1125. sums[index] = '';
  1126. }
  1127. });
  1128. return sums;
  1129. },
  1130. // ========== 批量编辑相关方法 ==========
  1131. /**
  1132. * 打开批量编辑弹窗
  1133. */
  1134. openBatchEditDialog() {
  1135. this.batchEditDialogVisible = true;
  1136. },
  1137. /**
  1138. * 加载批量编辑数据
  1139. * 将Box和明细数据扁平化为一个表格数据
  1140. */
  1141. async loadBatchEditData() {
  1142. this.batchEditLoading = true;
  1143. this.batchEditTableData = [];
  1144. this.batchEditOriginalData = {};
  1145. this.batchEditModifiedBoxes = {};
  1146. this.batchEditModifiedDetails = {};
  1147. this.batchEditSpanInfo = [];
  1148. try {
  1149. // 先获取Box列表
  1150. const boxResponse = await selectBoxList(this.currentRow);
  1151. if (!boxResponse.data || boxResponse.data.code !== 0) {
  1152. this.$message.error('加载箱数据失败');
  1153. return;
  1154. }
  1155. const boxes = boxResponse.data.rows || [];
  1156. const tableData = [];
  1157. const spanInfo = [];
  1158. // 遍历每个Box,获取其明细
  1159. for (const box of boxes) {
  1160. const detailParams = {
  1161. site: this.currentRow.site,
  1162. buNo: this.currentRow.buNo,
  1163. delNo: this.currentRow.delNo,
  1164. seqNo: box.item_no,
  1165. palletRemark: box.palletRemark
  1166. };
  1167. const detailResponse = await searchCoDelPalletDataNew(detailParams);
  1168. const details = (detailResponse.data && detailResponse.data.code === 0)
  1169. ? detailResponse.data.rows || []
  1170. : [];
  1171. // 记录该Box的起始行索引和跨行数
  1172. const startIndex = tableData.length;
  1173. const rowCount = details.length > 0 ? details.length : 1;
  1174. spanInfo.push({ startIndex, rowCount, boxKey: this.getBoxRowKey(box) });
  1175. if (details.length > 0) {
  1176. // 有明细时,为每个明细创建一行
  1177. details.forEach((detail, idx) => {
  1178. const rowData = {
  1179. // Box信息
  1180. _boxKey: this.getBoxRowKey(box),
  1181. _isFirstRowOfBox: idx === 0,
  1182. _rowSpan: idx === 0 ? details.length : 0,
  1183. item_no: box.item_no,
  1184. palletRemark: box.palletRemark,
  1185. box_qty: box.box_qty,
  1186. grossWeight: box.grossWeight,
  1187. netWeight: box.netWeight,
  1188. rolls: box.rolls, // Box的总Rolls
  1189. // 明细信息
  1190. _detailKey: `${detail.seqNo}_${detail.itemNo}_${detail.notifyDetailItemNo}`,
  1191. _hasDetail: true,
  1192. seqNo: detail.seqNo,
  1193. itemNo: detail.itemNo,
  1194. notifyDetailItemNo: detail.notifyDetailItemNo,
  1195. poNo: detail.poNo,
  1196. pn: detail.pn,
  1197. qty: detail.qty,
  1198. detailRolls: detail.rolls // 明细的Rolls
  1199. };
  1200. tableData.push(rowData);
  1201. // 保存原始数据
  1202. this.batchEditOriginalData[rowData._detailKey] = {
  1203. qty: detail.qty,
  1204. detailRolls: detail.rolls
  1205. };
  1206. });
  1207. // 保存Box原始数据,包括物料的箱重量
  1208. this.batchEditOriginalData[this.getBoxRowKey(box)] = {
  1209. box_qty: box.box_qty,
  1210. grossWeight: box.grossWeight,
  1211. netWeight: box.netWeight,
  1212. rolls: box.rolls,
  1213. boxWeight: box.boxWeight || 0 // 物料的箱重量(BOXWEIGHT)
  1214. };
  1215. } else {
  1216. // 没有明细时,创建一行空明细的数据
  1217. const rowData = {
  1218. _boxKey: this.getBoxRowKey(box),
  1219. _isFirstRowOfBox: true,
  1220. _rowSpan: 1,
  1221. item_no: box.item_no,
  1222. palletRemark: box.palletRemark,
  1223. box_qty: box.box_qty,
  1224. grossWeight: box.grossWeight,
  1225. netWeight: box.netWeight,
  1226. rolls: box.rolls, // Box的总Rolls
  1227. _hasDetail: false,
  1228. poNo: '',
  1229. pn: '',
  1230. qty: '',
  1231. detailRolls: ''
  1232. };
  1233. tableData.push(rowData);
  1234. // 保存Box原始数据,包括物料的箱重量
  1235. this.batchEditOriginalData[this.getBoxRowKey(box)] = {
  1236. box_qty: box.box_qty,
  1237. grossWeight: box.grossWeight,
  1238. netWeight: box.netWeight,
  1239. rolls: box.rolls,
  1240. boxWeight: box.boxWeight || 0 // 物料的箱重量(BOXWEIGHT)
  1241. };
  1242. }
  1243. }
  1244. this.batchEditTableData = tableData;
  1245. this.batchEditSpanInfo = spanInfo;
  1246. } catch (error) {
  1247. console.error('加载批量编辑数据失败:', error);
  1248. this.$message.error('加载数据失败');
  1249. } finally {
  1250. this.batchEditLoading = false;
  1251. }
  1252. },
  1253. /**
  1254. * 表格行合并方法
  1255. */
  1256. batchEditSpanMethod({ row, column, rowIndex, columnIndex }) {
  1257. // Box信息列(前5列:序号、箱数、毛重、净重、总Rolls)需要合并
  1258. if (columnIndex < 5) {
  1259. if (row._isFirstRowOfBox) {
  1260. return {
  1261. rowspan: row._rowSpan,
  1262. colspan: 1
  1263. };
  1264. } else {
  1265. return {
  1266. rowspan: 0,
  1267. colspan: 0
  1268. };
  1269. }
  1270. }
  1271. return {
  1272. rowspan: 1,
  1273. colspan: 1
  1274. };
  1275. },
  1276. /**
  1277. * 检查Box字段是否被修改
  1278. */
  1279. isBoxFieldModified(row, field) {
  1280. const boxKey = row._boxKey;
  1281. return this.batchEditModifiedBoxes[boxKey] &&
  1282. this.batchEditModifiedBoxes[boxKey][field] !== undefined;
  1283. },
  1284. /**
  1285. * 检查明细字段是否被修改
  1286. */
  1287. isDetailFieldModified(row, field) {
  1288. if (!row._hasDetail) return false;
  1289. const detailKey = row._detailKey;
  1290. return this.batchEditModifiedDetails[detailKey] &&
  1291. this.batchEditModifiedDetails[detailKey][field] !== undefined;
  1292. },
  1293. /**
  1294. * 批量编辑-箱数输入时联动计算毛重和净重
  1295. * 计算公式
  1296. * 1. 新毛重 = 物料箱重量(BOXWEIGHT) × 新箱数
  1297. * 2. 新净重 = 新毛重 - box_qty/2
  1298. */
  1299. onBatchBoxQtyInput(row) {
  1300. if (this._isBatchCalculating) return;
  1301. this._isBatchCalculating = true;
  1302. try {
  1303. const boxKey = row._boxKey;
  1304. const newBoxQty = parseFloat(row.box_qty) || 0;
  1305. // 从原始数据中获取物料的箱重量
  1306. const originalData = this.batchEditOriginalData[boxKey];
  1307. if (!originalData) return;
  1308. const boxWeight = parseFloat(originalData.boxWeight) || 0;
  1309. if (boxWeight <= 0) {
  1310. this.$message.warning('该物料未配置箱重量,无法自动计算毛重');
  1311. return;
  1312. }
  1313. // 根据物料箱重量计算新毛重:新毛重 = 箱重量 × 箱数
  1314. const newGrossWeight = boxWeight * newBoxQty;
  1315. // 计算新净重:净重 = 毛重 - box_qty/2
  1316. const newNetWeight = newGrossWeight - (newBoxQty / 2);
  1317. // 更新当前行
  1318. row.grossWeight = newGrossWeight.toFixed(3);
  1319. row.netWeight = newNetWeight.toFixed(3);
  1320. // 同步更新所有同Box的行
  1321. this.batchEditTableData.forEach(r => {
  1322. if (r._boxKey === boxKey) {
  1323. r.box_qty = row.box_qty;
  1324. r.grossWeight = row.grossWeight;
  1325. r.netWeight = row.netWeight;
  1326. }
  1327. });
  1328. // 触发毛重和净重的变化检测
  1329. this.onBatchBoxFieldChange(row, 'grossWeight');
  1330. this.onBatchBoxFieldChange(row, 'netWeight');
  1331. } finally {
  1332. this._isBatchCalculating = false;
  1333. }
  1334. },
  1335. /**
  1336. * 批量编辑-毛重输入时联动计算净重
  1337. * 计算公式净重 = 毛重 - box_qty/2
  1338. */
  1339. onBatchGrossWeightInput(row) {
  1340. if (this._isBatchCalculating) return;
  1341. this._isBatchCalculating = true;
  1342. try {
  1343. const grossWeight = parseFloat(row.grossWeight) || 0;
  1344. const boxQty = parseFloat(row.box_qty) || 0;
  1345. // 计算净重:净重 = 毛重 - box_qty/2
  1346. const netWeight = grossWeight - (boxQty / 2);
  1347. row.netWeight = netWeight.toFixed(2);
  1348. // 同步更新所有同Box的行
  1349. const boxKey = row._boxKey;
  1350. this.batchEditTableData.forEach(r => {
  1351. if (r._boxKey === boxKey) {
  1352. r.grossWeight = row.grossWeight;
  1353. r.netWeight = row.netWeight;
  1354. }
  1355. });
  1356. // 触发净重的变化检测
  1357. this.onBatchBoxFieldChange(row, 'netWeight');
  1358. } finally {
  1359. this._isBatchCalculating = false;
  1360. }
  1361. },
  1362. /**
  1363. * 批量编辑-净重输入时联动计算毛重
  1364. * 计算公式毛重 = 净重 + box_qty/2
  1365. */
  1366. onBatchNetWeightInput(row) {
  1367. if (this._isBatchCalculating) return;
  1368. this._isBatchCalculating = true;
  1369. try {
  1370. const netWeight = parseFloat(row.netWeight) || 0;
  1371. const boxQty = parseFloat(row.box_qty) || 0;
  1372. // 计算毛重:毛重 = 净重 + box_qty/2
  1373. const grossWeight = netWeight + (boxQty / 2);
  1374. row.grossWeight = grossWeight.toFixed(2);
  1375. // 同步更新所有同Box的行
  1376. const boxKey = row._boxKey;
  1377. this.batchEditTableData.forEach(r => {
  1378. if (r._boxKey === boxKey) {
  1379. r.netWeight = row.netWeight;
  1380. r.grossWeight = row.grossWeight;
  1381. }
  1382. });
  1383. // 触发毛重的变化检测
  1384. this.onBatchBoxFieldChange(row, 'grossWeight');
  1385. } finally {
  1386. this._isBatchCalculating = false;
  1387. }
  1388. },
  1389. /**
  1390. * Box字段变化处理
  1391. */
  1392. onBatchBoxFieldChange(row, field) {
  1393. const boxKey = row._boxKey;
  1394. const original = this.batchEditOriginalData[boxKey];
  1395. if (!original) return;
  1396. // 检查是否与原始值不同
  1397. const currentValue = String(row[field]);
  1398. const originalValue = String(original[field]);
  1399. if (currentValue !== originalValue) {
  1400. // 有变化,记录修改
  1401. if (!this.batchEditModifiedBoxes[boxKey]) {
  1402. this.$set(this.batchEditModifiedBoxes, boxKey, {});
  1403. }
  1404. this.$set(this.batchEditModifiedBoxes[boxKey], field, {
  1405. oldValue: original[field],
  1406. newValue: row[field]
  1407. });
  1408. // 同步更新所有同Box的行
  1409. this.batchEditTableData.forEach(r => {
  1410. if (r._boxKey === boxKey) {
  1411. r[field] = row[field];
  1412. }
  1413. });
  1414. } else {
  1415. // 恢复原值,移除修改记录
  1416. if (this.batchEditModifiedBoxes[boxKey]) {
  1417. this.$delete(this.batchEditModifiedBoxes[boxKey], field);
  1418. if (Object.keys(this.batchEditModifiedBoxes[boxKey]).length === 0) {
  1419. this.$delete(this.batchEditModifiedBoxes, boxKey);
  1420. }
  1421. }
  1422. }
  1423. },
  1424. /**
  1425. * 明细字段变化处理
  1426. */
  1427. onBatchDetailFieldChange(row, field) {
  1428. if (!row._hasDetail) return;
  1429. const detailKey = row._detailKey;
  1430. const original = this.batchEditOriginalData[detailKey];
  1431. if (!original) return;
  1432. const currentValue = String(row[field]);
  1433. const originalValue = String(original[field]);
  1434. if (currentValue !== originalValue) {
  1435. // 有变化,记录修改
  1436. if (!this.batchEditModifiedDetails[detailKey]) {
  1437. this.$set(this.batchEditModifiedDetails, detailKey, {
  1438. row: row // 保存行引用,方便后续提交
  1439. });
  1440. }
  1441. this.$set(this.batchEditModifiedDetails[detailKey], field, {
  1442. oldValue: original[field],
  1443. newValue: row[field]
  1444. });
  1445. } else {
  1446. // 恢复原值,移除修改记录
  1447. if (this.batchEditModifiedDetails[detailKey]) {
  1448. this.$delete(this.batchEditModifiedDetails[detailKey], field);
  1449. // 检查是否还有其他字段被修改
  1450. const remainingFields = Object.keys(this.batchEditModifiedDetails[detailKey])
  1451. .filter(k => k !== 'row');
  1452. if (remainingFields.length === 0) {
  1453. this.$delete(this.batchEditModifiedDetails, detailKey);
  1454. }
  1455. }
  1456. }
  1457. },
  1458. /**
  1459. * 明细Rolls输入事件处理 - 自动计算总Rolls
  1460. */
  1461. onDetailRollsInput(row) {
  1462. this.$nextTick(() => {
  1463. this.calculateBoxTotalRolls(row);
  1464. });
  1465. },
  1466. /**
  1467. * 计算同一Box下所有明细Rolls的总和
  1468. */
  1469. calculateBoxTotalRolls(row) {
  1470. const boxKey = row._boxKey;
  1471. // 获取同一Box下的所有行
  1472. const boxRows = this.batchEditTableData.filter(r => r._boxKey === boxKey && r._hasDetail);
  1473. // 计算明细Rolls总和
  1474. let totalDetailRolls = 0;
  1475. let hasDetailRolls = false;
  1476. boxRows.forEach(r => {
  1477. const rollsValue = parseFloat(r.detailRolls);
  1478. if (!isNaN(rollsValue) && rollsValue > 0) {
  1479. totalDetailRolls += rollsValue;
  1480. hasDetailRolls = true;
  1481. }
  1482. });
  1483. // 计算新的总Rolls值(有明细Rolls则计算,否则清空)
  1484. const newRolls = hasDetailRolls ? Math.round(totalDetailRolls) : null;
  1485. // 同步更新所有同Box的行的总Rolls
  1486. this.batchEditTableData.forEach(r => {
  1487. if (r._boxKey === boxKey) {
  1488. this.$set(r, 'rolls', newRolls);
  1489. }
  1490. });
  1491. // 触发Box字段变化检测
  1492. this.onBatchBoxFieldChange(row, 'rolls');
  1493. },
  1494. /**
  1495. * 检查Box是否有明细Rolls值用于禁用总Rolls输入
  1496. */
  1497. hasDetailRolls(row) {
  1498. const boxKey = row._boxKey;
  1499. const boxRows = this.batchEditTableData.filter(r => r._boxKey === boxKey && r._hasDetail);
  1500. return boxRows.some(r => {
  1501. const rollsValue = parseFloat(r.detailRolls);
  1502. return !isNaN(rollsValue) && rollsValue > 0;
  1503. });
  1504. },
  1505. /**
  1506. * 获取批量编辑行样式
  1507. */
  1508. getBatchEditRowClassName({ row, rowIndex }) {
  1509. const classes = [];
  1510. // 检查该行是否有Box修改
  1511. if (this.batchEditModifiedBoxes[row._boxKey]) {
  1512. classes.push('box-modified-row');
  1513. }
  1514. // 检查该行是否有明细修改
  1515. if (row._hasDetail && this.batchEditModifiedDetails[row._detailKey]) {
  1516. classes.push('detail-modified-row');
  1517. }
  1518. return classes.join(' ');
  1519. },
  1520. /**
  1521. * 保存批量编辑
  1522. */
  1523. async saveBatchEdit() {
  1524. if (this.batchEditModifiedCount === 0) {
  1525. this.$message.warning('没有需要保存的修改');
  1526. return;
  1527. }
  1528. this.batchEditSaving = true;
  1529. try {
  1530. // 构造Box修改列表
  1531. const boxList = [];
  1532. for (const boxKey of Object.keys(this.batchEditModifiedBoxes)) {
  1533. const row = this.batchEditTableData.find(r => r._boxKey === boxKey);
  1534. if (!row) continue;
  1535. boxList.push({
  1536. item_no: row.item_no,
  1537. palletRemark: row.palletRemark,
  1538. box_qty: row.box_qty,
  1539. grossWeight: row.grossWeight,
  1540. netWeight: row.netWeight,
  1541. rolls: row.rolls // Box的总Rolls
  1542. });
  1543. }
  1544. // 构造明细修改列表
  1545. const detailList = [];
  1546. for (const detailKey of Object.keys(this.batchEditModifiedDetails)) {
  1547. const detailMod = this.batchEditModifiedDetails[detailKey];
  1548. const row = detailMod.row;
  1549. if (!row) continue;
  1550. detailList.push({
  1551. seqNo: row.seqNo,
  1552. itemNo: row.itemNo,
  1553. notifyDetailItemNo: row.notifyDetailItemNo,
  1554. poNo: row.poNo,
  1555. pn: row.pn,
  1556. qty: row.qty,
  1557. rolls: row.detailRolls // 明细的Rolls
  1558. });
  1559. }
  1560. // 调用批量修改API
  1561. const batchParams = {
  1562. site: this.currentRow.site,
  1563. buNo: this.currentRow.buNo,
  1564. delNo: this.currentRow.delNo,
  1565. updateBy: this.$store.state.user.name,
  1566. boxList: boxList,
  1567. detailList: detailList
  1568. };
  1569. const response = await batchUpdatePackingInfo(batchParams);
  1570. if (response.data && response.data.code === 0) {
  1571. this.$message.success(`成功保存 ${this.batchEditModifiedCount} 处修改`);
  1572. this.batchEditDialogVisible = false;
  1573. this.loadBoxList(); // 刷新主表格
  1574. this.$emit('refresh'); // 刷新父页面列表
  1575. } else {
  1576. this.$alert(response.data.msg || '保存失败', '错误', {
  1577. confirmButtonText: '确定'
  1578. });
  1579. }
  1580. } catch (error) {
  1581. console.error('批量保存失败:', error);
  1582. this.$message.error('保存失败');
  1583. } finally {
  1584. this.batchEditSaving = false;
  1585. }
  1586. },
  1587. // ========== 调整总毛重相关方法 ==========
  1588. /**
  1589. * 打开调整总毛重弹窗
  1590. */
  1591. openAdjustWeightDialog() {
  1592. // 验证是否所有箱都已维护毛净重
  1593. if (this.dataListBoxes.length === 0) {
  1594. this.$message.warning('当前没有箱明细数据');
  1595. return;
  1596. }
  1597. // 检查是否所有箱都有毛重和净重
  1598. const hasInvalidBox = this.dataListBoxes.some(box => {
  1599. const grossWeight = parseFloat(box.grossWeight) || 0;
  1600. const netWeight = parseFloat(box.netWeight) || 0;
  1601. return grossWeight <= 0 || netWeight <= 0;
  1602. });
  1603. if (hasInvalidBox) {
  1604. this.$alert('请先为所有箱维护毛重和净重后再进行调整', '提示', {
  1605. confirmButtonText: '确定',
  1606. type: 'warning'
  1607. });
  1608. return;
  1609. }
  1610. // 初始化表单,默认值为当前合计毛重
  1611. this.adjustWeightForm.actualGrossWeight = '';
  1612. this.adjustWeightDialogVisible = true;
  1613. // 打开弹窗后自动聚焦到输入框并选中内容
  1614. this.$nextTick(() => {
  1615. if (this.$refs.actualWeightInput) {
  1616. this.$refs.actualWeightInput.focus();
  1617. this.$refs.actualWeightInput.select();
  1618. }
  1619. });
  1620. },
  1621. /**
  1622. * 提交调整总毛重
  1623. * 直接调用后端API由后端重新计算所有箱的毛重和净重
  1624. */
  1625. async submitAdjustWeight() {
  1626. // 验证输入
  1627. const actualGrossWeight = parseFloat(this.adjustWeightForm.actualGrossWeight);
  1628. if (isNaN(actualGrossWeight) || actualGrossWeight <= 0) {
  1629. this.$message.warning('请输入有效的实际总毛重');
  1630. return;
  1631. }
  1632. this.adjustWeightSaving = true;
  1633. try {
  1634. // 调用后端API进行调整
  1635. const adjustParams = {
  1636. site: this.currentRow.site,
  1637. buNo: this.currentRow.buNo,
  1638. delNo: this.currentRow.delNo,
  1639. actualGrossWeight: actualGrossWeight,
  1640. updateBy: this.$store.state.user.name
  1641. };
  1642. const response = await adjustTotalGrossWeight(adjustParams);
  1643. if (response.data && response.data.code === 0) {
  1644. this.$message.success('总毛重调整成功');
  1645. this.adjustWeightDialogVisible = false;
  1646. this.loadBoxList(); // 刷新主表格
  1647. this.$emit('refresh'); // 刷新父页面列表
  1648. } else {
  1649. this.$alert(response.data.msg || '调整失败', '错误', {
  1650. confirmButtonText: '确定'
  1651. });
  1652. }
  1653. } catch (error) {
  1654. console.error('调整总毛重失败:', error);
  1655. this.$message.error('调整失败');
  1656. } finally {
  1657. this.adjustWeightSaving = false;
  1658. }
  1659. }
  1660. }
  1661. }
  1662. </script>
  1663. <style scoped>
  1664. .packing-detail-tab {
  1665. width: 100%;
  1666. }
  1667. /* 托盘重量和总毛重显示样式(模拟表格行) */
  1668. .weight-summary-table {
  1669. border: 1px solid #ebeef5;
  1670. border-top: none;
  1671. background: #fff;
  1672. }
  1673. .weight-row {
  1674. display: flex;
  1675. border-bottom: 1px solid #ebeef5;
  1676. }
  1677. .weight-row:last-child {
  1678. border-bottom: none;
  1679. }
  1680. .weight-cell {
  1681. padding: 8px 10px;
  1682. border-right: 1px solid #ebeef5;
  1683. min-height: 23px;
  1684. box-sizing: border-box;
  1685. }
  1686. .weight-cell:last-child {
  1687. border-right: none;
  1688. }
  1689. /* 展开列 - 固定宽度50px */
  1690. .cell-expand {
  1691. width: 70px;
  1692. min-width: 50px;
  1693. max-width: 70px;
  1694. }
  1695. /* 标签列(序号列位置) - flex分配 */
  1696. .cell-label {
  1697. flex: 1;
  1698. min-width: 100px;
  1699. }
  1700. /* 数据列(箱数、毛重、净重、总Rolls) - flex分配 */
  1701. .cell-data {
  1702. flex: 1;
  1703. min-width: 80px;
  1704. text-align: right;
  1705. }
  1706. /* 操作列 - 固定宽度120px */
  1707. .cell-action {
  1708. width: 120px;
  1709. min-width: 120px;
  1710. max-width: 120px;
  1711. }
  1712. .label-cell {
  1713. color: #19be6b;
  1714. font-weight: bold;
  1715. }
  1716. .value-cell {
  1717. color: #19be6b;
  1718. font-weight: bold;
  1719. }
  1720. /* 展开明细容器样式 */
  1721. .expand-detail-container {
  1722. background: #fafafa;
  1723. border-radius: 6px;
  1724. overflow: visible;
  1725. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  1726. }
  1727. /* 加载状态样式 */
  1728. .expand-loading {
  1729. text-align: center;
  1730. padding: 30px;
  1731. color: #666;
  1732. background: #fafafa;
  1733. margin: 8px 16px;
  1734. border-radius: 6px;
  1735. }
  1736. .expand-loading i {
  1737. font-size: 18px;
  1738. margin-right: 8px;
  1739. color: #409eff;
  1740. }
  1741. /* 明细表格样式 */
  1742. .expand-detail-table {
  1743. margin: 0;
  1744. border: none;
  1745. }
  1746. /deep/ .expand-detail-table .el-table__body-wrapper {
  1747. overflow-y: auto;
  1748. }
  1749. /deep/ .expand-detail-table .el-table__header {
  1750. background: #f8f9fa;
  1751. }
  1752. /deep/ .expand-detail-table .el-table__header th {
  1753. background: #e6e8eb;
  1754. color: #333;
  1755. font-weight: 500;
  1756. border-bottom: 2px solid #e9ecef;
  1757. }
  1758. /deep/ .expand-detail-table .el-table__row:hover > td {
  1759. background-color: #f0f9ff;
  1760. }
  1761. /deep/ .expand-detail-table .el-table__row.el-table__row--striped {
  1762. background: #fbfcfd;
  1763. }
  1764. /deep/ .expand-detail-table .el-table__row.el-table__row--striped:hover > td {
  1765. background-color: #f0f9ff;
  1766. }
  1767. /* 空数据状态样式 */
  1768. .expand-empty-state {
  1769. text-align: center;
  1770. padding: 40px 20px;
  1771. color: #999;
  1772. }
  1773. .expand-empty-state i {
  1774. font-size: 70px;
  1775. color: #ddd;
  1776. margin-bottom: 12px;
  1777. display: block;
  1778. }
  1779. .expand-empty-state p {
  1780. font-size: 16px;
  1781. margin: 0 0 8px 0;
  1782. color: #666;
  1783. }
  1784. .expand-empty-state span {
  1785. font-size: 13px;
  1786. color: #999;
  1787. }
  1788. /* 响应式调整 */
  1789. @media (max-width: 768px) {
  1790. .expand-detail-container {
  1791. margin: 8px 8px;
  1792. padding: 6px;
  1793. }
  1794. }
  1795. /* 确保主表格容器的滚动行为 */
  1796. /deep/ .el-table__expanded-cell {
  1797. padding: 0 !important;
  1798. }
  1799. /deep/ .el-table__expand-column .cell {
  1800. padding: 0;
  1801. }
  1802. /* 确保表格滚动条正常显示 */
  1803. /deep/ .el-table .el-table__body-wrapper {
  1804. overflow-y: auto;
  1805. }
  1806. /deep/ .el-table__body-wrapper::-webkit-scrollbar {
  1807. width: 6px;
  1808. }
  1809. /deep/ .el-table__body-wrapper::-webkit-scrollbar-track {
  1810. background: #f1f1f1;
  1811. border-radius: 3px;
  1812. }
  1813. /deep/ .el-table__body-wrapper::-webkit-scrollbar-thumb {
  1814. background: #c1c1c1;
  1815. border-radius: 3px;
  1816. }
  1817. /deep/ .el-table__body-wrapper::-webkit-scrollbar-thumb:hover {
  1818. background: #a8a8a8;
  1819. }
  1820. /* 批量编辑工具栏 */
  1821. .batch-edit-toolbar {
  1822. margin-bottom: 10px;
  1823. display: flex;
  1824. justify-content: flex-start;
  1825. }
  1826. /* 批量编辑弹窗样式 */
  1827. /deep/ .batch-edit-dialog {
  1828. border-radius: 8px;
  1829. }
  1830. /deep/ .batch-edit-dialog .el-dialog__header {
  1831. background-color: #f5f7fa;
  1832. border-bottom: 1px solid #e4e7ed;
  1833. padding: 15px 20px;
  1834. border-radius: 8px 8px 0 0;
  1835. }
  1836. /deep/ .batch-edit-dialog .el-dialog__title {
  1837. font-size: 16px;
  1838. font-weight: 600;
  1839. color: #303133;
  1840. }
  1841. /deep/ .batch-edit-dialog .el-dialog__body {
  1842. padding: 15px 20px;
  1843. }
  1844. /deep/ .batch-edit-dialog .el-dialog__footer {
  1845. border-top: 1px solid #e4e7ed;
  1846. padding: 12px 20px;
  1847. }
  1848. /* 批量编辑弹窗容器 */
  1849. .batch-edit-container {
  1850. min-height: 300px;
  1851. }
  1852. /* 批量编辑提示 */
  1853. .batch-edit-tips {
  1854. margin-bottom: 15px;
  1855. }
  1856. .batch-edit-tips .modified-count {
  1857. color: #e6a23c;
  1858. margin-left: 10px;
  1859. }
  1860. .batch-edit-tips .modified-count b {
  1861. color: #f56c6c;
  1862. font-size: 16px;
  1863. }
  1864. /* 批量编辑表格样式 */
  1865. /deep/ .batch-edit-container .el-table {
  1866. border-radius: 4px;
  1867. border: 1px solid #ebeef5;
  1868. }
  1869. /* 表头样式 - 确保表头可见 */
  1870. /deep/ .batch-edit-container .el-table__header-wrapper {
  1871. background-color: #f5f7fa;
  1872. }
  1873. /deep/ .batch-edit-container .el-table th {
  1874. background-color: #f5f7fa !important;
  1875. color: #606266 !important;
  1876. font-weight: 600;
  1877. font-size: 13px;
  1878. padding: 8px 0;
  1879. }
  1880. /deep/ .batch-edit-container .el-table th .cell {
  1881. color: #606266 !important;
  1882. font-weight: 600;
  1883. }
  1884. /* Box信息单元格样式 */
  1885. .box-info-cell {
  1886. font-weight: 600;
  1887. color: #409eff;
  1888. font-size: 13px;
  1889. }
  1890. /* 修改过的输入框样式 */
  1891. /deep/ .batch-edit-container .modified-input .el-input__inner {
  1892. background-color: #fff7e6;
  1893. border-color: #e6a23c;
  1894. color: #e6a23c;
  1895. }
  1896. /* 修改过的行样式 */
  1897. /deep/ .batch-edit-container .box-modified-row td:nth-child(-n+4) {
  1898. background-color: #fdf6ec !important;
  1899. }
  1900. /deep/ .batch-edit-container .detail-modified-row td:nth-child(n+5) {
  1901. background-color: #fff7e6 !important;
  1902. }
  1903. /* 输入框样式 */
  1904. /deep/ .batch-edit-container .el-input--mini .el-input__inner {
  1905. text-align: center;
  1906. padding: 0 8px;
  1907. border-color: #dcdfe6;
  1908. }
  1909. /deep/ .batch-edit-container .el-input--mini .el-input__inner:focus {
  1910. border-color: #409eff;
  1911. }
  1912. /* 表格单元格内边距 */
  1913. /deep/ .batch-edit-container .el-table td {
  1914. padding: 6px 0;
  1915. }
  1916. /deep/ .batch-edit-container .el-table .cell {
  1917. padding: 0 8px;
  1918. }
  1919. /* 数字输入框隐藏上下箭头 */
  1920. /deep/ .batch-edit-container input[type="number"]::-webkit-inner-spin-button,
  1921. /deep/ .batch-edit-container input[type="number"]::-webkit-outer-spin-button {
  1922. -webkit-appearance: none;
  1923. margin: 0;
  1924. }
  1925. /deep/ .batch-edit-container input[type="number"] {
  1926. -moz-appearance: textfield;
  1927. }
  1928. /* 合并单元格的垂直居中 */
  1929. /deep/ .batch-edit-container .el-table__body td[rowspan] {
  1930. vertical-align: middle;
  1931. }
  1932. /deep/ .batch-edit-container .el-table__body td[rowspan] .cell {
  1933. display: flex;
  1934. align-items: center;
  1935. justify-content: center;
  1936. height: 100%;
  1937. }
  1938. /* 文字样式 */
  1939. /deep/ .batch-edit-container .el-table .cell span {
  1940. font-size: 13px;
  1941. color: #606266;
  1942. }
  1943. /* ========== 调整总毛重弹窗样式 ========== */
  1944. /* 重量显示 */
  1945. .weight-display {
  1946. font-size: 20px;
  1947. font-weight: bold;
  1948. color: #409eff;
  1949. font-family: 'Courier New', monospace;
  1950. }
  1951. .weight-display-small {
  1952. font-size: 16px;
  1953. font-weight: 600;
  1954. color: #606266;
  1955. font-family: 'Courier New', monospace;
  1956. }
  1957. /* 输入框高亮 */
  1958. .input-highlight /deep/ .el-input__inner {
  1959. height: 50px;
  1960. font-size: 12px;
  1961. font-weight: 600;
  1962. border: 2px solid #409eff;
  1963. font-family: 'Courier New', monospace;
  1964. background-color: #f0f9ff;
  1965. }
  1966. .input-highlight /deep/ .el-input__inner:focus {
  1967. border-color: #409eff;
  1968. box-shadow: 0 0 8px rgba(64, 158, 255, 0.3);
  1969. }
  1970. .input-highlight /deep/ .el-input-group__append {
  1971. background-color: #409eff;
  1972. color: #fff;
  1973. border: 2px solid #409eff;
  1974. border-left: none;
  1975. font-weight: 600;
  1976. font-size: 16px;
  1977. }
  1978. .input-highlight /deep/ .el-form-item__label {
  1979. font-size: 12px;
  1980. font-weight: 600;
  1981. color: #303133;
  1982. }
  1983. </style>