yyb
5 天以前 23ff9ba58505814008984ffd4b8125cc67b9cc12
src/views/salesManagement/salesLedger/index.vue
@@ -25,13 +25,20 @@
    </div>
    <div class="table_list">
      <div class="actions">
        <div></div>
        <div>
          <OtherAmountMaintenanceButton />
          <ProcessFlowMaintenanceButton />
        </div>
        <ProcessFlowConfigSelectDialog
          v-model:visible="processFlowSelectDialogVisible"
          @confirm="handleProcessFlowSelectConfirm"
        />
        <div>
          <el-button type="primary" @click="openForm('add')">
            新增台账
          </el-button>
          <el-button type="primary" plain @click="openOtherAmountDialog">
            其他金额维护
        <el-button type="primary"  @click="handleBulkDelivery">
            发货
          </el-button>
          <el-button type="primary" plain @click="handleImport">导入</el-button>
          <el-button @click="handleOut">导出</el-button>
@@ -49,7 +56,11 @@
              <el-table-column align="center" label="序号" type="index"/>
              <el-table-column label="产品大类" prop="productCategory" />
              <el-table-column label="规格型号" prop="specificationModel" />
              <el-table-column label="单位" prop="unit" />
              <el-table-column label="厚度" prop="thickness" min-width="90">
                <template #default="scope">
                  {{ scope.row.thickness ?? "" }}
                </template>
              </el-table-column>
                     <el-table-column label="产品状态"
                                              width="100px"
                                              align="center">
@@ -96,7 +107,7 @@
              <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
              <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
            <!--操作-->
              <el-table-column Width="60px" label="操作" align="center">
              <!-- <el-table-column Width="60px" label="操作" align="center">
                <template #default="scope">
                  <el-button 
                    link 
@@ -106,7 +117,7 @@
                    发货
                  </el-button>
                </template>
              </el-table-column>
              </el-table-column> -->
            </el-table>
          </template>
        </el-table-column>
@@ -123,9 +134,10 @@
        <el-table-column label="签订日期" prop="executionDate" width="120" show-overflow-tooltip />
        <el-table-column label="交付日期" prop="deliveryDate" width="120" show-overflow-tooltip />
        <el-table-column label="备注" prop="remarks" width="200" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" width="130" align="center">
        <el-table-column fixed="right" label="操作" width="200" align="center">
          <template #default="scope">
            <el-button link type="primary" @click="openForm('edit', scope.row)" :disabled="!scope.row.isEdit">编辑</el-button>
            <el-button link type="primary" @click="openProcessFlowSelect(scope.row)" :disabled="!scope.row.isEdit">工艺路线</el-button>
            <el-button link type="primary" @click="downLoadFile(scope.row)">附件</el-button>
          </template>
        </el-table-column>
@@ -229,7 +241,11 @@
               <el-table-column align="center" label="序号" type="index" width="60" />
               <el-table-column label="产品大类" prop="productCategory" />
               <el-table-column label="规格型号" prop="specificationModel" />
               <el-table-column label="单位" prop="unit" />
               <el-table-column label="厚度" prop="thickness" min-width="90">
                  <template #default="scope">
                     {{ scope.row.thickness ?? "" }}
                  </template>
               </el-table-column>
               <el-table-column label="数量" prop="quantity" />
               <el-table-column label="税率(%)" prop="taxRate" />
               <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
@@ -247,6 +263,20 @@
               <el-col :span="24">
                  <el-form-item label="备注:" prop="remarks">
                     <el-input v-model="form.remarks" placeholder="请输入" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" />
                  </el-form-item>
               </el-col>
            </el-row>
            <el-row :gutter="30">
               <el-col :span="24">
                  <el-form-item label="客户备注:" prop="customerRemarks">
                     <el-input
                        v-model="form.customerRemarks"
                        placeholder="请输入"
                        clearable
                        type="textarea"
                        :rows="2"
                        :disabled="operationType === 'view'"
                     />
                  </el-form-item>
               </el-col>
            </el-row>
@@ -374,8 +404,16 @@
                  </el-form-item>
               </el-col>
               <el-col :span="8">
                  <el-form-item label="单位:" prop="unit">
                     <el-input v-model="productForm.unit" placeholder="请输入" clearable />
                  <el-form-item label="厚度:" prop="thickness">
                     <el-input-number
                        v-model="productForm.thickness"
                        :min="0"
                        :step="0.000000000000001"
                        :precision="15"
                        style="width: 100%;"
                        placeholder="请输入"
                        clearable
                     />
                  </el-form-item>
               </el-col>
            </el-row>
@@ -564,6 +602,13 @@
                  </el-form-item>
               </el-col>
            </el-row>
            <el-row :gutter="30">
               <el-col :span="24">
                  <el-form-item label="楼层编号:" prop="floorCode">
                     <el-input v-model="productForm.floorCode" placeholder="请输入楼层编号" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" />
                  </el-form-item>
               </el-col>
            </el-row>
            <!-- 其他金额(占满一行:等同于 3 列网格的整行) -->
            <el-row :gutter="30">
               <el-col :span="12">
@@ -684,6 +729,7 @@
            </el-button>
         </template>
      </el-dialog>
      <!-- 导入弹窗 -->
      <FormDialog
         v-model="importUpload.open"
@@ -778,7 +824,7 @@
                           <tr>
                              <th>产品名称</th>
                              <th>规格型号</th>
                              <th>单位</th>
                              <th>厚度</th>
                              <th>单价</th>
                              <th>零售数量</th>
                              <th>零售金额</th>
@@ -788,7 +834,7 @@
                           <tr v-for="product in item.products" :key="product.id">
                              <td>{{ product.productCategory || '' }}</td>
                              <td>{{ product.specificationModel || '' }}</td>
                              <td>{{ product.unit || '' }}</td>
                              <td>{{ product.thickness ?? '' }}</td>
                              <td>{{ product.taxInclusiveUnitPrice || '0' }}</td>
                              <td>{{ product.quantity || '0' }}</td>
                              <td>{{ product.taxInclusiveTotalPrice || '0' }}</td>
@@ -916,114 +962,6 @@
         </template>
      </el-dialog>
      <!-- 其他金额维护(新增/编辑/删除) -->
      <el-dialog
         v-model="otherAmountDialogVisible"
         title="其他金额维护"
         width="80%"
         :close-on-click-modal="false"
         @close="closeOtherAmountDialog"
      >
         <el-row :gutter="20">
            <el-col :span="14">
               <el-table
                  :data="otherAmountRecords"
                  border
                  v-loading="otherAmountLoading"
                  height="55vh"
               >
                  <el-table-column label="编码" prop="code" min-width="120" show-overflow-tooltip />
                  <el-table-column label="项目" prop="processName" min-width="180" show-overflow-tooltip />
                  <el-table-column label="数量" prop="quantity" min-width="110" :formatter="formattedNumber" />
                  <el-table-column label="单价(元)" prop="unitPrice" min-width="130" :formatter="formattedNumber" />
                  <el-table-column label="金额(元)" prop="amount" min-width="160" :formatter="formattedNumber" />
                  <el-table-column fixed="right" label="操作" width="160" align="center">
                     <template #default="scope">
                        <el-button link type="primary" size="small" @click="handleOtherEdit(scope.row)">编辑</el-button>
                        <el-button link type="danger" size="small" @click="handleOtherDelete(scope.row)">删除</el-button>
                     </template>
                  </el-table-column>
               </el-table>
               <pagination
                  v-show="otherAmountTotal > 0"
                  :total="otherAmountTotal"
                  layout="total, sizes, prev, pager, next, jumper"
                  :page="otherAmountPage.current"
                  :limit="otherAmountPage.size"
                  @pagination="otherAmountPaginationChange"
               />
            </el-col>
            <el-col :span="10">
               <div style="padding: 8px 0;">
                  <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom: 10px;">
                     <div style="font-weight:600;">
                        {{ otherAmountOperationType === 'add' ? '新增其他金额' : '编辑其他金额' }}
                     </div>
                     <el-button
                        type="primary"
                        plain
                        size="small"
                        @click="handleOtherAdd"
                        :disabled="otherAmountOperationType === 'add'"
                     >
                        新增
                     </el-button>
                  </div>
                  <el-form
                     :model="otherAmountForm"
                     label-width="120px"
                     label-position="top"
                     :rules="otherAmountRules"
                     ref="otherAmountFormRef"
                  >
                     <el-form-item label="编码">
                        <el-input v-model="otherAmountForm.code" placeholder="请输入编码(可选)" clearable />
                     </el-form-item>
                     <el-form-item label="项目" prop="processName">
                        <el-input v-model="otherAmountForm.processName" placeholder="请输入项目名称" clearable />
                     </el-form-item>
                     <el-form-item label="数量" prop="quantity">
                        <el-input-number
                           v-model="otherAmountForm.quantity"
                           :min="0"
                           :precision="2"
                           style="width:100%"
                           placeholder="请输入数量"
                           clearable
                           @change="recalcOtherAmount"
                        />
                     </el-form-item>
                     <el-form-item label="单价(元)" prop="unitPrice">
                        <el-input-number
                           v-model="otherAmountForm.unitPrice"
                           :min="0"
                           :precision="2"
                           style="width:100%"
                           placeholder="请输入单价"
                           clearable
                           @change="recalcOtherAmount"
                        />
                     </el-form-item>
                     <el-form-item label="金额(元)">
                        <el-input v-model="otherAmountForm.amount" disabled />
                     </el-form-item>
                     <div style="display:flex; justify-content:flex-end; gap: 10px; margin-top: 8px;">
                        <el-button @click="closeOtherAmountDialog">取消</el-button>
                        <el-button type="primary" @click="submitOtherAmountForm">保存</el-button>
                     </div>
                  </el-form>
               </div>
            </el-col>
         </el-row>
      </el-dialog>
   </div>
</template>
@@ -1038,6 +976,9 @@
import { userListNoPage } from "@/api/system/user.js";
import FileListDialog from '@/components/Dialog/FileListDialog.vue';
import FormDialog from '@/components/Dialog/FormDialog.vue';
import OtherAmountMaintenanceButton from "./components/OtherAmountMaintenanceButton.vue";
import ProcessFlowMaintenanceButton from "./components/ProcessFlowMaintenanceButton.vue";
import ProcessFlowConfigSelectDialog from "./components/ProcessFlowConfigSelectDialog.vue";
import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
import {
   ledgerListPage,
@@ -1051,14 +992,12 @@
   delLedgerFile,
   getProductInventory,
   salesLedgerProductProcessList,
   salesLedgerProductProcessAdd,
   salesLedgerProductProcessUpdate,
   salesLedgerProductProcessDelete,
} from "@/api/salesManagement/salesLedger.js";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import useFormData from "@/hooks/useFormData.js";
import dayjs from "dayjs";
import { getCurrentDate } from "@/utils/index.js";
import { salesLedgerProductSetProcessFlowConfig } from "@/api/salesManagement/salesProcessFlowConfig.js";
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
@@ -1077,6 +1016,10 @@
});
const total = ref(0);
const fileList = ref([]);
// 工艺路线配置选择弹窗(绑定到台账产品)
const processFlowSelectDialogVisible = ref(false);
const processFlowSelectLedgerRow = ref(null);
// 用户信息表单弹框数据
const operationType = ref("");
@@ -1119,7 +1062,7 @@
   productForm: {
      productCategory: "",
      specificationModel: "",
      unit: "",
      thickness:null,
      quantity: "",
      taxInclusiveUnitPrice: "",
      taxRate: "",
@@ -1138,6 +1081,8 @@
      processRequirement: "", // 加工要求
      remark: "", // 备注
      salesProductProcessList: [], // 其他金额:[{id, processName, quantity}]
      processFlowConfigId: null, // 工艺流程配置绑定
      floorCode: "", // 楼层编号
   },
   productRules: {
      productCategory: [{ required: true, message: "请选择", trigger: "change" }],
@@ -1145,7 +1090,7 @@
      specificationModel: [
         { required: true, message: "请选择", trigger: "change" },
      ],
      unit: [{ required: true, message: "请输入", trigger: "blur" }],
      thickness: [{ required: true, message: "请输入", trigger: "blur" }],
      quantity: [{ required: true, message: "请输入", trigger: "blur" }],
      taxInclusiveUnitPrice: [
         { required: true, message: "请输入", trigger: "blur" },
@@ -1191,7 +1136,7 @@
// 发货相关
const deliveryFormVisible = ref(false);
const currentDeliveryRow = ref(null);
const currentDeliveryRows = ref([]);
const deliveryFormData = reactive({
  deliveryForm: {
    type: "货车", // 货车, 快递
@@ -1203,169 +1148,6 @@
  },
});
const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
// 其他金额维护(工序/流程金额维护)
const otherAmountDialogVisible = ref(false);
const otherAmountLoading = ref(false);
const otherAmountRecords = ref([]);
const otherAmountTotal = ref(0);
const otherAmountPage = reactive({
   current: 1,
   size: 10,
});
const otherAmountOperationType = ref("add"); // add/edit
const otherAmountFormRef = ref(null);
const otherAmountForm = reactive({
   id: null,
   code: "", // 前端字段名:code;后端接口列表返回 remark,此处进行映射
   processName: "",
   quantity: 0,
   unitPrice: 0,
   amount: "0.00",
});
const otherAmountRules = reactive({
   processName: [{ required: true, message: "请输入项目名称", trigger: "change" }],
   quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
   unitPrice: [{ required: true, message: "请输入单价", trigger: "blur" }],
});
const recalcOtherAmount = () => {
   const quantity = Number(otherAmountForm.quantity ?? 0) || 0;
   const unitPrice = Number(otherAmountForm.unitPrice ?? 0) || 0;
   otherAmountForm.amount = (quantity * unitPrice).toFixed(2);
};
const resetOtherAmountForm = (type = "add") => {
   otherAmountOperationType.value = type;
   otherAmountForm.id = null;
   otherAmountForm.code = "";
   otherAmountForm.processName = "";
   otherAmountForm.quantity = 0;
   otherAmountForm.unitPrice = 0;
   otherAmountForm.amount = "0.00";
};
const openOtherAmountDialog = () => {
   otherAmountDialogVisible.value = true;
   resetOtherAmountForm("add");
   // 打开弹框时刷新数据,避免长时间停留导致数据过期
   otherAmountPage.current = otherAmountPage.current || 1;
   fetchOtherAmountList();
};
const closeOtherAmountDialog = () => {
   otherAmountDialogVisible.value = false;
   resetOtherAmountForm("add");
};
const fetchOtherAmountList = async () => {
   otherAmountLoading.value = true;
   try {
      const params = {
         current: otherAmountPage.current,
         size: otherAmountPage.size,
      };
      const res = await salesLedgerProductProcessList(params);
      // 兼容不同接口响应结构:可能是 res.records / res.total 或 res.data.records / res.data.total
      const records = res?.records ?? res?.data?.records ?? [];
      const total = res?.total ?? res?.data?.total ?? 0;
      otherAmountRecords.value = records.map((item) => {
         const quantity = Number(item.quantity ?? 0) || 0;
         const unitPrice = Number(item.unitPrice ?? 0) || 0;
         const amount = Number(item.amount ?? quantity * unitPrice) || 0;
         return {
            id: item.id,
            code: item.code ?? item.remark ?? "",
            processName: item.processName ?? "",
            quantity,
            unitPrice,
            amount: amount.toFixed(2),
         };
      });
      otherAmountTotal.value = total;
   } finally {
      otherAmountLoading.value = false;
   }
};
const otherAmountPaginationChange = (obj) => {
   otherAmountPage.current = obj.page;
   otherAmountPage.size = obj.limit;
   fetchOtherAmountList();
};
const handleOtherAdd = () => {
   resetOtherAmountForm("add");
};
const handleOtherEdit = (row) => {
   if (!row) return;
   otherAmountOperationType.value = "edit";
   otherAmountForm.id = row.id ?? null;
   otherAmountForm.code = row.code ?? "";
   otherAmountForm.processName = row.processName ?? "";
   otherAmountForm.quantity = Number(row.quantity ?? 0) || 0;
   otherAmountForm.unitPrice = Number(row.unitPrice ?? 0) || 0;
   recalcOtherAmount();
};
const submitOtherAmountForm = () => {
   otherAmountFormRef.value?.validate((valid) => {
      if (!valid) return;
      const payload = {
         processName: otherAmountForm.processName,
         quantity: Number(otherAmountForm.quantity) || 0,
         unitPrice: Number(otherAmountForm.unitPrice) || 0,
         amount: Number(otherAmountForm.amount) || 0,
         // 列表返回字段是 remark,这里按“code=remark”做映射
         remark: otherAmountForm.code,
         // 兼容后端可能直接使用 code 字段
         code: otherAmountForm.code,
      };
      if (otherAmountOperationType.value === "edit") {
         payload.id = otherAmountForm.id;
         salesLedgerProductProcessUpdate(payload).then(() => {
            proxy.$modal.msgSuccess("保存成功");
            fetchOtherAmountList();
            resetOtherAmountForm("add");
         });
      } else {
         salesLedgerProductProcessAdd(payload).then(() => {
            proxy.$modal.msgSuccess("保存成功");
            fetchOtherAmountList();
            resetOtherAmountForm("add");
         });
      }
   });
};
const handleOtherDelete = (row) => {
   if (!row?.id) return;
   ElMessageBox.confirm("确认删除该记录?", "删除", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
   })
      .then(() => {
         return salesLedgerProductProcessDelete(row.id).then(() => {
            proxy.$modal.msgSuccess("删除成功");
            fetchOtherAmountList();
            if (otherAmountOperationType.value === "edit" && otherAmountForm.id === row.id) {
               resetOtherAmountForm("add");
            }
         });
      })
      .catch(() => {
         proxy.$modal.msg("已取消");
      });
};
// 产品弹框:其他金额多选下拉(基于“其他金额维护”查询接口)
const otherAmountSelectOptions = ref([]); // [{id, processName}]
@@ -1636,6 +1418,59 @@
         tableLoading.value = false;
      });
};
// 打开“工艺路线配置”选择弹窗(必须显式选择)
const openProcessFlowSelect = (ledgerRow) => {
   if (!ledgerRow) return;
   if (!ledgerRow.isEdit) return;
   processFlowSelectLedgerRow.value = ledgerRow;
   processFlowSelectDialogVisible.value = true;
};
// 将配置应用到台账下的所有未发货产品
const handleProcessFlowSelectConfirm = async (configId) => {
   const ledgerRow = processFlowSelectLedgerRow.value;
   if (!ledgerRow?.id) return;
   const finalConfigId = configId ?? null;
   if (!finalConfigId) return;
   proxy?.$modal?.loading?.("正在应用工艺路线配置,请稍候...");
   try {
      const res = await productList({ salesLedgerId: ledgerRow.id, type: 1 });
      const products = res?.data ?? res?.records ?? res ?? [];
      if (!Array.isArray(products) || products.length === 0) {
         proxy?.$modal?.msgWarning?.("该台账下没有产品数据");
         return;
      }
      for (const product of products) {
         // 已发货/审核通过不可编辑,跳过
         if (isProductShipped(product)) continue;
         await salesLedgerProductSetProcessFlowConfig({
            salesLedgerProductId: product.id,
            processFlowConfigId: finalConfigId,
         });
      }
      proxy?.$modal?.msgSuccess?.("工艺路线配置应用成功");
      // 若当前行已展开,刷新其子产品列表
      if (expandedRowKeys.value.includes(ledgerRow.id)) {
         const childRes = await productList({ salesLedgerId: ledgerRow.id, type: 1 });
         const children = childRes?.data ?? childRes?.records ?? childRes ?? [];
         const index = tableData.value.findIndex((item) => item.id === ledgerRow.id);
         if (index > -1) {
            tableData.value[index].children = children;
         }
      }
   } catch (e) {
      proxy?.$modal?.msgError?.("应用失败,请稍后重试");
   } finally {
      proxy?.$modal?.closeLoading?.();
   }
};
// 获取产品大类tree数据
const getProductOptions = () => {
   // 返回 Promise,便于在编辑产品时等待加载完成
@@ -1658,10 +1493,8 @@
   const index = modelOptions.value.findIndex((item) => item.id === value);
   if (index !== -1) {
      productForm.value.specificationModel = modelOptions.value[index].model;
      productForm.value.unit = modelOptions.value[index].unit;
   } else {
      productForm.value.specificationModel = null;
      productForm.value.unit = null;
   }
};
const findNodeById = (nodes, productId) => {
@@ -1784,11 +1617,14 @@
      form.value.entryDate = getCurrentDate();
      // 签订日期默认为当天
      form.value.executionDate = getCurrentDate();
      form.value.customerRemarks = "";
   } else {
      currentId.value = row.id;
      getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
         form.value = { ...res };
         form.value.entryPerson = Number(res.entryPerson);
         // 字段名兼容:后端可能返回 customer_remarks
         form.value.customerRemarks = res?.customerRemarks ?? res?.customer_remarks ?? "";
         productData.value = form.value.productData;
         fileList.value = form.value.salesLedgerFiles;
      });
@@ -1886,7 +1722,7 @@
         // 台账字段
         productCategory: p.product || p.productName || "",
         specificationModel: p.specification || "",
         unit: p.unit || "",
         thickness: p.thickness,
         quantity: quantity,
         taxRate: taxRate,
         taxInclusiveUnitPrice: unitPrice.toFixed(2),
@@ -1901,6 +1737,7 @@
         settlePieceArea: 0,
         settleTotalArea: 0,
         processRequirement: "",
         floorCode: "",
         remark: "",
         salesProductProcessList: [],
      };
@@ -2007,10 +1844,17 @@
      productForm.value.processRequirement =
         row?.processRequirement ?? row?.process_requirement ?? "";
      productForm.value.remark = row?.remark ?? row?.remarks ?? "";
      productForm.value.floorCode = row?.floorCode ?? row?.floor_code ?? "";
      // 工艺流程配置绑定字段(后续由后端确认字段名)
      productForm.value.processFlowConfigId =
         row?.processFlowConfigId ?? row?.process_flow_config_id ?? null;
      // 周长回显(如后端返回;最终仍以公式计算为准)
      productForm.value.perimeter =
         row?.perimeter ?? row?.heavyBoxPerimeter ?? row?.heavyboxPerimeter ?? 0;
      // 后端直接返回 thickness
      productForm.value.thickness = row?.thickness;
      productForm.value.salesProductProcessList = normalizeOtherAmountsFromRow(row);
      productIndex.value = index;
@@ -2055,6 +1899,11 @@
const submitProduct = () => {
   proxy.$refs["productFormRef"].validate((valid) => {
      if (valid) {
         // 厚度保留 15 位小数,避免由于浮点计算/输入导致精度偏差
         if (productForm.value.thickness !== null && productForm.value.thickness !== undefined) {
            productForm.value.thickness = Number(Number(productForm.value.thickness).toFixed(15));
         }
         // 面积/总计字段在提交前兜底计算一次
         recalcAreaTotals();
         // 其他金额只提交 {id, processName, quantity}(后端字段:salesProductProcessList)
@@ -2471,7 +2320,7 @@
                <tr>
                  <th>产品名称</th>
                  <th>规格型号</th>
                  <th>单位</th>
                  <th>厚度</th>
                  <th>单价</th>
                  <th>零售数量</th>
                  <th>零售金额</th>
@@ -2483,7 +2332,7 @@
                    <tr>
                      <td>${product.productCategory || ''}</td>
                      <td>${product.specificationModel || ''}</td>
                      <td>${product.unit || ''}</td>
                      <td>${product.thickness ?? ''}</td>
                      <td>${product.taxInclusiveUnitPrice || '0'}</td>
                      <td>${product.quantity || '0'}</td>
                      <td>${product.taxInclusiveTotalPrice || '0'}</td>
@@ -2926,6 +2775,72 @@
   return statusStr === '待发货' || statusStr === '审核拒绝';
};
const handleBulkDelivery = async () => {
   if (selectedRows.value.length === 0) {
      proxy.$modal.msgWarning("请选择数据");
      return;
   }
   const customerNames = selectedRows.value.map((r) => String(r.customerName || "").trim());
   const uniqueCustomers = Array.from(new Set(customerNames));
   // 客户名称不一致不允许发货
   if (uniqueCustomers.length > 1) {
      proxy.$modal.msgWarning("客户名称不一致,不允许发货");
      return;
   }
   // 多条且客户一致:二次确认
   if (selectedRows.value.length > 1) {
      try {
         await ElMessageBox.confirm("是否确认合并发货?", "合并发货", {
            confirmButtonText: "确认",
            cancelButtonText: "取消",
            type: "warning",
         });
      } catch (e) {
         proxy.$modal.msg("已取消");
         return;
      }
   }
   proxy.$modal.loading("正在获取产品数据,请稍候...");
   try {
      const targets = [];
      for (const ledger of selectedRows.value) {
         let products = [];
         try {
            const res = await productList({ salesLedgerId: ledger.id, type: 1 });
            products = res?.data || [];
         } catch {
            products = [];
         }
         for (const product of products) {
            if (!canShip(product)) continue;
            targets.push({
               ...product,
               salesLedgerId: product.salesLedgerId || ledger.id,
            });
         }
      }
      if (targets.length === 0) {
         proxy.$modal.msgWarning("没有可发货的数据");
         return;
      }
      currentDeliveryRows.value = targets;
      deliveryForm.value = { type: "货车" };
      // 重置审批人节点(默认一个空节点)
      approverNodes.value = [{ id: 1, userId: null }];
      nextApproverId = 2;
      deliveryFormVisible.value = true;
   } finally {
      proxy.$modal.closeLoading();
   }
};
/**
 * 下载文件
 *
@@ -2949,7 +2864,7 @@
      return;
   }
   
   currentDeliveryRow.value = row;
   currentDeliveryRows.value = [row];
  deliveryForm.value = {
    type: "货车",
  };
@@ -2972,13 +2887,28 @@
      const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
      // 保存当前展开的行ID,以便发货后重新加载子表格数据
      const currentExpandedKeys = [...expandedRowKeys.value];
      const salesLedgerId = currentDeliveryRow.value.salesLedgerId;
      addShippingInfo({
        salesLedgerId: salesLedgerId,
        salesLedgerProductId: currentDeliveryRow.value.id,
        type: deliveryForm.value.type,
            approveUserIds,
      })
      const targets = currentDeliveryRows.value || [];
      if (targets.length === 0) {
        proxy.$modal.msgWarning("未选择可发货的数据");
        return;
      }
      // 依次发货(避免并发下库存扣减/状态更新互相影响)
      const run = async () => {
        for (const item of targets) {
          const salesLedgerId = item.salesLedgerId;
          if (!salesLedgerId) continue;
          await addShippingInfo({
            salesLedgerId,
            salesLedgerProductId: item.id,
            type: deliveryForm.value.type,
            approveUserIds,
          });
        }
      };
      run()
        .then(() => {
          proxy.$modal.msgSuccess("发货成功");
          closeDeliveryDia();
@@ -2986,8 +2916,7 @@
          getList().then(() => {
            // 如果之前有展开的行,重新加载这些行的子表格数据
            if (currentExpandedKeys.length > 0) {
              // 使用 Promise.all 并行加载所有展开行的子表格数据
              const loadPromises = currentExpandedKeys.map(ledgerId => {
              const loadPromises = currentExpandedKeys.map((ledgerId) => {
                return productList({ salesLedgerId: ledgerId, type: 1 }).then((res) => {
                  const index = tableData.value.findIndex((item) => item.id === ledgerId);
                  if (index > -1) {
@@ -2996,12 +2925,14 @@
                });
              });
              Promise.all(loadPromises).then(() => {
                // 恢复展开状态
                expandedRowKeys.value = currentExpandedKeys;
              });
            }
          });
        })
        .catch(() => {
          proxy.$modal.msgError("发货失败,请稍后重试");
        });
    }
  });
};
@@ -3010,7 +2941,7 @@
const closeDeliveryDia = () => {
  proxy.resetForm("deliveryFormRef");
  deliveryFormVisible.value = false;
  currentDeliveryRow.value = null;
  currentDeliveryRows.value = [];
};
const currentFactoryName = ref("");
const getCurrentFactoryName = async () => {