mlchen 2 өдөр өмнө
parent
commit
9fa1627435

+ 610 - 73
src/views/warehouseManagement/stockLedger/components/BatchChangeDialog.vue

@@ -2,16 +2,102 @@
   <el-dialog
     :title="dialogTitle"
     :visible.sync="visible"
-    width="1050px"
+    width="92%"
     :close-on-click-modal="false"
     @close="reset"
   >
     <template v-if="mode === 'records'">
+      <el-form
+        size="mini"
+        label-width="72px"
+        class="record-search"
+        @submit.native.prevent="searchRecords"
+      >
+        <el-row :gutter="16">
+          <el-col :xs="24" :md="12" :lg="5">
+            <el-form-item label="审核代码">
+              <el-input
+                v-model="recordQuery.changeNo"
+                clearable
+                placeholder="请输入审核代码"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :md="12" :lg="5">
+            <el-form-item label="审批人">
+              <el-input
+                v-model="recordQuery.approverName"
+                clearable
+                placeholder="请输入审批人"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :md="12" :lg="5">
+            <el-form-item label="仓库名称">
+              <el-input
+                v-model="recordQuery.warehouseName"
+                clearable
+                placeholder="请输入仓库名称"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :md="12" :lg="5">
+            <el-form-item label="批次号">
+              <el-input
+                v-model="recordQuery.batchNo"
+                clearable
+                placeholder="请输入批次号"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :md="12" :lg="5">
+            <el-form-item label="物品编码">
+              <el-input
+                v-model="recordQuery.categoryCode"
+                clearable
+                placeholder="请输入物品编码"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :md="12" :lg="5">
+            <el-form-item label="类型">
+              <el-select
+                v-model="recordQuery.changeType"
+                clearable
+                placeholder="请选择类型"
+              >
+                <el-option label="拆批" :value="1" />
+                <el-option label="合批" :value="2" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :md="12" :lg="5">
+            <el-form-item label="审批状态">
+              <el-select
+                v-model="recordQuery.verifyStatus"
+                clearable
+                placeholder="请选择审批状态"
+              >
+                <el-option
+                  v-for="item in verifyStatusOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :lg="4" class="record-search-actions">
+            <el-button type="primary" @click="searchRecords">查询</el-button>
+            <el-button @click="resetRecordQuery">重置</el-button>
+          </el-col>
+        </el-row>
+      </el-form>
       <ele-pro-table
         ref="recordTable"
         :columns="recordColumns"
         :datasource="recordSource"
-        height="450px"
+        height="600px"
         :pageSize="10"
       >
         <template v-slot:status="{ row }">
@@ -43,6 +129,7 @@
       <el-alert
         v-if="mode === 'merge'"
         title="仅允许同仓库、批次号、物品属性、供应商和价格完全一致的库存合批,审批通过后生成新系统批次。"
+        style="color: red"
         type="info"
         :closable="false"
       />
@@ -64,7 +151,7 @@
       <el-table :data="sources" size="mini" border>
         <el-table-column
           prop="systemBatchNo"
-          label="来源系统批次"
+          label="来源系统批次"
           min-width="150"
         />
         <el-table-column prop="batchNo" label="业务批次" />
@@ -94,6 +181,8 @@
                 :disabled="Boolean(pendingApproveId)"
                 size="mini"
                 placeholder="请输入"
+                @input="markMeasureQuantityManual(row.target)"
+                @blur="validateTargetLimit(row.target, 'measureQuantity')"
               />
             </template>
           </el-table-column>
@@ -118,6 +207,7 @@
                 :disabled="Boolean(pendingApproveId)"
                 size="mini"
                 placeholder="请输入"
+                @blur="validateTargetLimit(row.target, 'weight')"
               />
             </template>
           </el-table-column>
@@ -149,7 +239,43 @@
 
       <template v-if="packingRows.length">
         <div class="section-title">整包装分配</div>
-        <el-table :data="packingRows" size="mini" border max-height="260">
+        <div v-if="mode === 'split'" class="packing-batch-actions">
+          <span>已选择 {{ selectedPackingRows.length }} 个整包装</span>
+          <el-select
+            v-model="batchPackingTargetId"
+            size="mini"
+            :disabled="Boolean(pendingApproveId)"
+            placeholder="请选择目标子批次"
+          >
+            <el-option
+              v-for="target in targets"
+              :key="target.targetDetailId"
+              :label="targetLabel(target.targetDetailId)"
+              :value="target.targetDetailId"
+            />
+          </el-select>
+          <el-button
+            type="primary"
+            size="mini"
+            :disabled="Boolean(pendingApproveId)"
+            @click="assignSelectedPackingTarget"
+            >批量分配</el-button
+          >
+        </div>
+        <el-table
+          ref="packingTable"
+          :data="packingRows"
+          size="mini"
+          border
+          max-height="260"
+          @selection-change="handlePackingSelectionChange"
+        >
+          <el-table-column
+            v-if="mode === 'split'"
+            type="selection"
+            width="45"
+            :selectable="packingRowSelectable"
+          />
           <el-table-column
             prop="systemBatchNo"
             label="来源系统批次"
@@ -243,68 +369,178 @@
     <el-dialog
       title="批次变更申请详情"
       :visible.sync="detailVisible"
-      width="850px"
+      width="95%"
       append-to-body
     >
-      <el-descriptions
-        v-loading="detailLoading"
-        :column="3"
-        border
-        size="small"
-      >
-        <el-descriptions-item label="审核代码">{{
-          detailData.changeNo || '-'
-        }}</el-descriptions-item>
-        <el-descriptions-item label="变更类型">{{
-          detailData.changeType === 1 ? '拆批' : '合批'
-        }}</el-descriptions-item>
-        <el-descriptions-item label="审批状态">{{
-          statusText(detailData.verifyStatus)
-        }}</el-descriptions-item>
-        <el-descriptions-item label="仓库">{{
-          detailData.warehouseName || '-'
-        }}</el-descriptions-item>
-        <el-descriptions-item label="申请时间">{{
-          detailData.createTime || '-'
-        }}</el-descriptions-item>
-        <el-descriptions-item label="说明">{{
-          detailData.remark || '-'
-        }}</el-descriptions-item>
-      </el-descriptions>
-      <el-table
-        :data="detailData.details || []"
-        size="mini"
-        border
-        class="detail-table"
-      >
-        <el-table-column prop="sourceStockBatchId" label="来源批次ID" />
-        <el-table-column
-          prop="systemBatchNo"
-          label="来源系统批次"
-          min-width="140"
-        />
-        <el-table-column
-          prop="targetSystemBatchNo"
-          label="目标系统批次"
-          min-width="140"
-        />
-        <el-table-column prop="measureQuantity" label="计量数量" />
-        <el-table-column prop="packageQuantity" label="包装数量" />
-        <el-table-column prop="weight" label="重量" />
-        <el-table-column prop="lockQuantity" label="锁库数量" />
-        <el-table-column
-          prop="packingStockIds"
-          label="包装库存分配"
-          min-width="180"
-          show-overflow-tooltip
-        />
-        <el-table-column
-          prop="lockAllocations"
-          label="锁定单分配"
-          min-width="220"
-          show-overflow-tooltip
-        />
-      </el-table>
+      <el-tabs v-model="detailTab" v-loading="detailLoading">
+        <el-tab-pane label="业务详情" name="business">
+          <el-descriptions :column="3" border size="small">
+            <el-descriptions-item label="审核代码">{{
+              detailData.changeNo || '-'
+            }}</el-descriptions-item>
+            <el-descriptions-item label="变更类型">{{
+              detailData.changeType === 1 ? '拆批' : '合批'
+            }}</el-descriptions-item>
+            <el-descriptions-item label="审批状态">{{
+              statusText(detailData.verifyStatus)
+            }}</el-descriptions-item>
+            <el-descriptions-item label="当前审批人">{{
+              detailData.currentApproverName || '-'
+            }}</el-descriptions-item>
+            <el-descriptions-item label="仓库">{{
+              detailData.warehouseName || '-'
+            }}</el-descriptions-item>
+            <el-descriptions-item label="申请时间">{{
+              detailData.createTime || '-'
+            }}</el-descriptions-item>
+            <el-descriptions-item label="说明">{{
+              detailData.remark || '-'
+            }}</el-descriptions-item>
+          </el-descriptions>
+          <el-table
+            :data="detailData.details || []"
+            size="mini"
+            border
+            class="detail-table"
+          >
+            <el-table-column
+              prop="systemBatchNo"
+              label="来源系统批次号"
+              min-width="140"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.systemBatchNo)
+              }}</template>
+            </el-table-column>
+            <el-table-column prop="batchNo" label="业务批次" min-width="110">
+              <template slot-scope="{ row }">{{
+                displayValue(row.batchNo)
+              }}</template>
+            </el-table-column>
+            <el-table-column
+              prop="warehouseName"
+              label="仓库名称"
+              min-width="120"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.warehouseName)
+              }}</template>
+            </el-table-column>
+            <el-table-column
+              prop="categoryCode"
+              label="物品编码"
+              min-width="120"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.categoryCode)
+              }}</template>
+            </el-table-column>
+            <el-table-column
+              prop="categoryName"
+              label="物品名称"
+              min-width="120"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.categoryName)
+              }}</template>
+            </el-table-column>
+            <el-table-column prop="specification" label="规格" min-width="100">
+              <template slot-scope="{ row }">{{
+                displayValue(row.specification)
+              }}</template>
+            </el-table-column>
+            <el-table-column prop="categoryModel" label="型号" min-width="100">
+              <template slot-scope="{ row }">{{
+                displayValue(row.categoryModel)
+              }}</template>
+            </el-table-column>
+            <el-table-column prop="brandNum" label="牌号" min-width="100">
+              <template slot-scope="{ row }">{{
+                displayValue(row.brandNum)
+              }}</template>
+            </el-table-column>
+            <el-table-column prop="colorKey" label="颜色" min-width="100">
+              <template slot-scope="{ row }">{{
+                displayValue(row.colorKey)
+              }}</template>
+            </el-table-column>
+            <el-table-column prop="unitPrice" label="单价" min-width="100">
+              <template slot-scope="{ row }">{{
+                displayValue(row.unitPrice)
+              }}</template>
+            </el-table-column>
+            <el-table-column
+              prop="supplierName"
+              label="供应商名称"
+              min-width="130"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.supplierName)
+              }}</template>
+            </el-table-column>
+            <el-table-column
+              prop="supplierCode"
+              label="供应商代号"
+              min-width="120"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.supplierCode)
+              }}</template>
+            </el-table-column>
+            <el-table-column
+              prop="targetSystemBatchNo"
+              label="目标系统批次"
+              min-width="140"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.targetSystemBatchNo || targetBatchText(row))
+              }}</template>
+            </el-table-column>
+            <el-table-column
+              prop="measureQuantity"
+              label="计量数量"
+              min-width="100"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.measureQuantity)
+              }}</template>
+            </el-table-column>
+            <el-table-column
+              prop="packageQuantity"
+              label="包装数量"
+              min-width="100"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.packageQuantity)
+              }}</template>
+            </el-table-column>
+            <el-table-column prop="weight" label="重量" min-width="90">
+              <template slot-scope="{ row }">{{
+                displayValue(row.weight)
+              }}</template>
+            </el-table-column>
+            <el-table-column
+              prop="lockQuantity"
+              label="锁库数量"
+              min-width="100"
+            >
+              <template slot-scope="{ row }">{{
+                displayValue(row.lockQuantity)
+              }}</template>
+            </el-table-column>
+          </el-table>
+        </el-tab-pane>
+        <el-tab-pane
+          v-if="detailProcessInstanceId"
+          label="流程详情"
+          name="process"
+        >
+          <bpm-detail
+            v-if="detailTab === 'process'"
+            :id="detailProcessInstanceId"
+          />
+        </el-tab-pane>
+      </el-tabs>
     </el-dialog>
   </el-dialog>
 </template>
@@ -312,6 +548,7 @@
 <script>
   import BigNumber from 'bignumber.js';
   import stockBatchChange from '@/api/warehouseManagement/stockBatchChange';
+  import bpmDetail from '@/views/bpm/processInstance/detail.vue';
 
   function decimal(value) {
     const result = new BigNumber(value == null || value === '' ? 0 : value);
@@ -341,6 +578,7 @@
   const DECIMAL_INPUT_PATTERN = /^\d{1,12}(?:\.\d{1,6})?$/;
 
   export default {
+    components: { bpmDetail },
     data() {
       return {
         visible: false,
@@ -353,11 +591,30 @@
         detailVisible: false,
         detailLoading: false,
         detailData: {},
+        detailTab: 'business',
         pendingApproveId: null,
-        recordActionId: null
+        recordActionId: null,
+        selectedPackingRows: [],
+        batchPackingTargetId: null,
+        recordQuery: {
+          changeNo: '',
+          approverName: '',
+          warehouseName: '',
+          batchNo: '',
+          categoryCode: '',
+          changeType: null,
+          verifyStatus: null
+        }
       };
     },
     computed: {
+      detailProcessInstanceId() {
+        return (
+          this.detailData.processInstanceId ||
+          this.detailData.flowableTaskId ||
+          ''
+        );
+      },
       dialogTitle() {
         if (this.mode === 'records') return '批次变更申请记录';
         return this.mode === 'split' ? '库存拆批申请' : '库存合批申请';
@@ -409,7 +666,84 @@
             label: '类型',
             formatter: (row) => (row.changeType === 1 ? '拆批' : '合批')
           },
+          {
+            prop: 'warehouseName',
+            label: '仓库名称',
+            minWidth: 120,
+            formatter: (row) => this.recordValues(row, 'warehouseName')
+          },
+          {
+            prop: 'batchNo',
+            label: '业务批次',
+            minWidth: 110,
+            formatter: (row) => this.recordValues(row, 'batchNo')
+          },
+          {
+            prop: 'systemBatchNo',
+            label: '来源系统批次号',
+            minWidth: 150,
+            formatter: (row) => this.recordValues(row, 'systemBatchNo')
+          },
+          {
+            prop: 'categoryCode',
+            label: '物品编码',
+            minWidth: 120,
+            formatter: (row) => this.recordValues(row, 'categoryCode')
+          },
+          {
+            prop: 'categoryName',
+            label: '物品名称',
+            minWidth: 120,
+            formatter: (row) => this.recordValues(row, 'categoryName')
+          },
+          {
+            prop: 'specification',
+            label: '规格',
+            minWidth: 100,
+            formatter: (row) => this.recordValues(row, 'specification')
+          },
+          {
+            prop: 'categoryModel',
+            label: '型号',
+            minWidth: 100,
+            formatter: (row) => this.recordValues(row, 'categoryModel')
+          },
+          {
+            prop: 'brandNum',
+            label: '牌号',
+            minWidth: 100,
+            formatter: (row) => this.recordValues(row, 'brandNum')
+          },
+          {
+            prop: 'colorKey',
+            label: '颜色',
+            minWidth: 90,
+            formatter: (row) => this.recordValues(row, 'colorKey')
+          },
+          {
+            prop: 'unitPrice',
+            label: '单价',
+            minWidth: 90,
+            formatter: (row) => this.recordValues(row, 'unitPrice')
+          },
+          {
+            prop: 'supplierName',
+            label: '供应商名称',
+            minWidth: 130,
+            formatter: (row) => this.recordValues(row, 'supplierName')
+          },
+          {
+            prop: 'supplierCode',
+            label: '供应商代号',
+            minWidth: 120,
+            formatter: (row) => this.recordValues(row, 'supplierCode')
+          },
           { prop: 'verifyStatus', slot: 'status', label: '审批状态' },
+          {
+            prop: 'currentApproverName',
+            label: '当前审批人',
+            formatter: (row) => row.currentApproverName || '-'
+          },
           { prop: 'createTime', label: '申请时间' },
           {
             columnKey: 'action',
@@ -419,14 +753,24 @@
             fixed: 'right'
           }
         ];
+      },
+      verifyStatusOptions() {
+        return [
+          { value: 1, label: '审批中' },
+          { value: 2, label: '已通过' },
+          { value: 3, label: '已驳回' },
+          { value: 4, label: '已撤回' }
+        ];
       }
     },
     methods: {
       async open(mode, rows) {
         this.mode = mode;
         this.pendingApproveId = null;
-        this.visible = true;
-        if (mode === 'records') return;
+        if (mode === 'records') {
+          this.visible = true;
+          return;
+        }
         this.sourceLoading = true;
         try {
           const selectedRows = rows || [];
@@ -449,8 +793,8 @@
               ? [this.createTarget(1)]
               : [this.createTarget(1), this.createTarget(2)];
           if (mode === 'merge') this.assignMergeTarget();
+          this.visible = true;
         } catch (error) {
-          this.visible = false;
           this.$message.error(error.message || '批次来源详情加载失败');
         } finally {
           this.sourceLoading = false;
@@ -498,6 +842,7 @@
         return {
           targetDetailId,
           measureQuantity: '0',
+          measureQuantityManual: false,
           packageQuantity: '0',
           weight: '0'
         };
@@ -508,7 +853,11 @@
         this.remark = '';
         this.detailVisible = false;
         this.detailData = {};
+        this.detailTab = 'business';
         this.pendingApproveId = null;
+        this.selectedPackingRows = [];
+        this.batchPackingTargetId = null;
+        this.clearRecordQuery();
       },
       addTarget() {
         const maxId = this.targets.reduce(
@@ -531,6 +880,9 @@
         this.targets = this.targets.filter(
           (target) => target.targetDetailId !== targetDetailId
         );
+        if (this.batchPackingTargetId === targetDetailId) {
+          this.batchPackingTargetId = null;
+        }
       },
       assignMergeTarget() {
         this.packingRows.forEach((row) => {
@@ -545,8 +897,76 @@
         target.weight = this.sum(this.sources, 'weight');
         this.syncTargetPackingMinimums();
       },
+      handlePackingSelectionChange(rows) {
+        this.selectedPackingRows = rows;
+      },
+      packingRowSelectable() {
+        if (this.pendingApproveId || !this.batchPackingTargetId) return false;
+        const target = this.targets.find(
+          (item) => item.targetDetailId === this.batchPackingTargetId
+        );
+        return Boolean(target && !isEmptyDecimal(target.measureQuantity));
+      },
+      /** 将勾选的整包装一次分配到同一目标子批次。 */
+      assignSelectedPackingTarget() {
+        if (!this.batchPackingTargetId) {
+          return this.$message.warning('请选择目标子批次');
+        }
+        const target = this.targets.find(
+          (item) => item.targetDetailId === this.batchPackingTargetId
+        );
+        if (!target || isEmptyDecimal(target.measureQuantity)) {
+          return this.$message.warning('请先填写目标子批次的计量数量');
+        }
+        const assignedMeasureQuantity = this.packingRows
+          .filter((row) => row.targetDetailId === target.targetDetailId)
+          .reduce(
+            (sum, row) => sum.plus(decimal(row.measureQuantity)),
+            new BigNumber(0)
+          );
+        const remainingMeasureQuantity = decimal(target.measureQuantity).minus(
+          assignedMeasureQuantity
+        );
+        if (remainingMeasureQuantity.lte(0)) {
+          return this.$message.warning('该目标子批次已按计量数量分配整包装');
+        }
+        const selectedRows = [];
+        let selectedMeasureQuantity = new BigNumber(0);
+        this.packingRows
+          .filter((row) => !row.targetDetailId)
+          .some((packing) => {
+            const packingMeasureQuantity = decimal(packing.measureQuantity);
+            if (
+              selectedMeasureQuantity
+                .plus(packingMeasureQuantity)
+                .gt(remainingMeasureQuantity)
+            ) {
+              return false;
+            }
+            selectedRows.push(packing);
+            selectedMeasureQuantity = selectedMeasureQuantity.plus(
+              packingMeasureQuantity
+            );
+            return selectedMeasureQuantity.eq(remainingMeasureQuantity);
+          });
+        if (!selectedRows.length) {
+          return this.$message.warning('没有可按该计量数量分配的整包装');
+        }
+        selectedRows.forEach((packing) => {
+          packing.targetDetailId = this.batchPackingTargetId;
+          this.assignPackingTarget(packing, this.batchPackingTargetId, false);
+        });
+        this.syncTargetPackingMinimums();
+        this.selectedPackingRows = selectedRows;
+        this.$refs.packingTable.clearSelection();
+        this.$nextTick(() => {
+          selectedRows.forEach((packing) => {
+            this.$refs.packingTable.toggleRowSelection(packing, true);
+          });
+        });
+      },
       /** 包装分配变化时,同步其关联锁定单的全部明细和包装。 */
-      assignPackingTarget(packing, targetDetailId) {
+      assignPackingTarget(packing, targetDetailId, shouldSync = true) {
         const relatedLocks = this.lockRows.filter((lock) =>
           lock.lockedPackingStockIds.some(
             (id) => String(id) === String(packing.packingStockId)
@@ -555,7 +975,7 @@
         if (relatedLocks.length) {
           this.assignConnectedLockRows(relatedLocks, targetDetailId);
         }
-        this.syncTargetPackingMinimums();
+        if (shouldSync) this.syncTargetPackingMinimums();
       },
       /** 锁定单必须整单分配,且所有关联包装必须与锁定单落到同一目标。 */
       assignLockOrderTarget(lock, targetDetailId) {
@@ -608,7 +1028,10 @@
           );
           const measureMinimum = decimal(this.sum(packages, 'measureQuantity'));
           const weightMinimum = decimal(this.sum(packages, 'weight'));
-          if (decimal(target.measureQuantity).lt(measureMinimum)) {
+          if (
+            !target.measureQuantityManual ||
+            decimal(target.measureQuantity).lt(measureMinimum)
+          ) {
             target.measureQuantity = measureMinimum.toFixed(6);
           }
           if (decimal(target.weight).lt(weightMinimum)) {
@@ -616,6 +1039,28 @@
           }
         });
       },
+      markMeasureQuantityManual(target) {
+        target.measureQuantityManual = true;
+      },
+      validateTargetLimit(target, field) {
+        if (this.mode !== 'split' || !this.sources.length) return;
+        const source = this.sources[0];
+        const sourceField =
+          field === 'measureQuantity' ? 'stockCountBase' : 'weight';
+        const total = decimal(
+          this.targets.reduce(
+            (sum, target) => sum.plus(decimal(target[field])),
+            new BigNumber(0)
+          )
+        );
+        const limit = decimal(source[sourceField]);
+        if (total.lte(limit)) return;
+        const label = field === 'measureQuantity' ? '计量数量' : '重量';
+        target[field] = '';
+        this.$message.warning(
+          `目标子批次${label}累计不能超过来源库存${label} ${limit.toFixed(6)}`
+        );
+      },
       targetLabel(id) {
         return this.mode === 'merge' ? '合并目标' : `子批次 ${id}`;
       },
@@ -648,13 +1093,56 @@
       statusType(value) {
         return value === 2 ? 'success' : value === 3 ? 'danger' : 'info';
       },
+      displayValue(value) {
+        return value == null || value === '' ? '-' : value;
+      },
+      recordValues(row, key) {
+        const values = [
+          row[key],
+          ...(row.details || []).map((item) => item[key])
+        ]
+          .filter((value) => value != null && value !== '')
+          .map((value) => String(value));
+        return [...new Set(values)].join('、') || '-';
+      },
+      targetBatchText(row) {
+        return row.targetDetailId
+          ? `目标 ${row.targetDetailId}(审批通过后生成)`
+          : '审批通过后生成';
+      },
       recordSource({ page, limit, where }) {
-        return stockBatchChange.page({ ...where, pageNum: page, size: limit });
+        return stockBatchChange.page({
+          ...where,
+          ...this.recordQuery,
+          pageNum: page,
+          size: limit
+        });
+      },
+      searchRecords() {
+        if (this.$refs.recordTable) {
+          this.$refs.recordTable.reload({ page: 1 });
+        }
+      },
+      clearRecordQuery() {
+        this.recordQuery = {
+          changeNo: '',
+          approverName: '',
+          warehouseName: '',
+          batchNo: '',
+          categoryCode: '',
+          changeType: null,
+          verifyStatus: null
+        };
+      },
+      resetRecordQuery() {
+        this.clearRecordQuery();
+        this.searchRecords();
       },
       async showDetail(row) {
         this.detailVisible = true;
         this.detailLoading = true;
         this.detailData = {};
+        this.detailTab = 'business';
         try {
           this.detailData = (await stockBatchChange.detail(row.id)) || {};
         } catch (error) {
@@ -787,6 +1275,25 @@
           )
         )
           return '目标子批次锁库数量不能大于计量数量';
+        const source = this.sources[0];
+        if (this.mode === 'split') {
+          const targetMeasureQuantity = decimal(
+            this.sum(this.targetRows, 'measureQuantity')
+          );
+          const sourceMeasureQuantity = decimal(source.stockCountBase);
+          if (targetMeasureQuantity.gt(sourceMeasureQuantity)) {
+            return `目标子批次计量数量累计不能超过来源库存数量 ${sourceMeasureQuantity.toFixed(
+              6
+            )}`;
+          }
+          const targetWeight = decimal(this.sum(this.targetRows, 'weight'));
+          const sourceWeight = decimal(source.weight);
+          if (targetWeight.gt(sourceWeight)) {
+            return `目标子批次重量累计不能超过来源库存重量 ${sourceWeight.toFixed(
+              6
+            )}`;
+          }
+        }
         if (
           this.hasPacking &&
           this.targetRows.some(
@@ -797,7 +1304,6 @@
           )
         )
           return '目标计量数量和重量不能小于所选整包装汇总';
-        const source = this.sources[0];
         if (this.mode === 'split') {
           if (
             !decimal(this.sum(this.targetRows, 'measureQuantity')).eq(
@@ -932,10 +1438,41 @@
 </script>
 
 <style scoped>
+  .record-search {
+    padding: 14px 16px 2px;
+    margin-bottom: 12px;
+    background-color: #f5f7fa;
+    border: 1px solid #ebeef5;
+  }
+  .record-search :deep(.el-form-item),
+  .record-search :deep(.el-select) {
+    width: 100%;
+  }
+  .record-search-actions {
+    display: flex;
+    justify-content: flex-end;
+    padding-top: 1px;
+  }
+  @media (max-width: 1199px) {
+    .record-search-actions {
+      justify-content: flex-start;
+      padding: 0 8px 12px;
+    }
+  }
   .section-title {
     margin: 14px 0 8px;
     font-weight: 600;
   }
+  .packing-batch-actions {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    margin-bottom: 8px;
+    color: #606266;
+  }
+  .packing-batch-actions .el-select {
+    width: 180px;
+  }
   .merge-summary {
     padding: 14px 0 0;
     color: #606266;

+ 8 - 0
src/views/warehouseManagement/stockLedger/components/item-list.vue

@@ -759,6 +759,14 @@
           return this.$message.warning('拆批请选择一条库存批次');
         if (mode === 'merge' && this.checkRadioData.length < 2)
           return this.$message.warning('合批请选择至少两条库存批次');
+        if (
+          this.checkRadioData.some(
+            (row) =>
+              row.stockCountBase != null && Number(row.stockCountBase) === 0
+          )
+        ) {
+          return this.$message.warning('数量为0的库存批次不支持拆批和合批');
+        }
         this.$refs.batchChangeRef.open(mode, this.checkRadioData);
       },