src/views/salesManagement/salesLedger/index.vue
@@ -41,6 +41,12 @@
            <el-option label="已发货" :value="4" />
          </el-select>
        </el-form-item>
        <el-form-item label="入库状态:">
          <el-select v-model="searchForm.stockStatus" placeholder="请选择" clearable style="width: 140px">
            <el-option label="未入库" :value="0" />
            <el-option label="已入库" :value="1" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleQuery"> 搜索 </el-button>
        </el-form-item>
@@ -59,6 +65,7 @@
          @confirm="handleProcessFlowSelectConfirm"
        />
         <el-space wrap>
               <el-button type="primary" @click="handleSalesStock">入库</el-button>
               <el-button type="primary" @click="openForm('add')">新增台账</el-button>
               <el-button type="primary" @click="handleBulkDelivery">发货</el-button>
               <el-button type="primary" plain @click="handleImport">导入</el-button>
@@ -204,6 +211,13 @@
                  <el-tag v-else type="info">-</el-tag>
               </template>
        </el-table-column>
        <el-table-column label="入库状态" width="120" align="center">
            <template #default="scope">
                  <el-tag v-if="Number(scope.row.stockStatus) === 0" type="info">未入库</el-tag>
                  <el-tag v-else-if="Number(scope.row.stockStatus) === 1" type="success">已入库</el-tag>
                  <el-tag v-else type="info">-</el-tag>
               </template>
        </el-table-column>
        <el-table-column label="录入人" prop="entryPersonName" width="100" show-overflow-tooltip />
        <el-table-column label="录入日期" prop="entryDate" width="120" show-overflow-tooltip />
        <el-table-column label="签订日期" prop="executionDate" width="120" show-overflow-tooltip />
@@ -298,7 +312,14 @@
            </el-row>
            <el-row>
               <el-form-item label="产品信息:" prop="entryDate">
                  <el-button v-if="operationType !== 'view'" type="primary" @click="addProductInline">添加</el-button>
                  <el-button
                     v-if="operationType !== 'view'"
                     type="primary"
                     :disabled="hasEditingProductRow()"
                     @click="addProductInline"
                  >
                     添加
                  </el-button>
                  <el-button v-if="operationType !== 'view'" plain type="danger" @click="deleteProduct" >删除</el-button>
               </el-form-item>
            </el-row>
@@ -325,7 +346,7 @@
                     <span v-else>{{ scope.row.productCategory ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="规格型号" prop="specificationModel" min-width="140">
               <el-table-column label="规格型号" prop="specificationModel" min-width="160">
                  <template #default="scope">
                     <el-select
                        v-if="scope.row.__editing"
@@ -333,7 +354,7 @@
                        placeholder="请选择"
                        clearable
                        filterable
                        style="width: 140px"
                        style="width: 100%"
                        @change="(val) => handleInlineProductModelChange(scope.row, val)"
                     >
                        <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
@@ -341,7 +362,7 @@
                     <span v-else>{{ scope.row.specificationModel ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="厚度" prop="thickness" min-width="90">
               <el-table-column label="厚度(mm)" prop="thickness" min-width="160">
                  <template #default="scope">
                     <el-input-number
                        v-if="scope.row.__editing"
@@ -349,14 +370,14 @@
                        :min="0"
                        :step="0.000000000000001"
                        :precision="15"
                        style="width: 110px"
                        style="width: 100%"
                        placeholder="请输入"
                        clearable
                     />
                     <span v-else>{{ scope.row.thickness ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="宽(mm)" prop="width" min-width="80">
               <el-table-column label="宽(mm)" prop="width" min-width="160">
                  <template #default="scope">
                     <el-input-number
                        v-if="scope.row.__editing"
@@ -364,15 +385,16 @@
                        :min="0"
                        :step="1"
                        :precision="2"
                        style="width: 110px"
                        style="width:100%"
                        placeholder="请输入"
                        clearable
                        @change="() => handleInlineSizeChange(scope.row)"
                        @input="() => handleInlineSizeChange(scope.row)"
                     />
                     <span v-else>{{ scope.row.width ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="高(mm)" prop="height" min-width="80">
               <el-table-column label="高(mm)" prop="height" min-width="160">
                  <template #default="scope">
                     <el-input-number
                        v-if="scope.row.__editing"
@@ -380,30 +402,32 @@
                        :min="0"
                        :step="1"
                        :precision="2"
                        style="width: 110px"
                        style="width: 100%"
                        placeholder="请输入"
                        clearable
                        @change="() => handleInlineSizeChange(scope.row)"
                        @input="() => handleInlineSizeChange(scope.row)"
                     />
                     <span v-else>{{ scope.row.height ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="面积(m²)" prop="actualTotalArea" min-width="100">
               <el-table-column label="结算单片面积(㎡)" prop="settlePieceArea" min-width="160">
                  <template #default="scope">
                     <el-input-number
                        v-if="scope.row.__editing"
                        v-model="scope.row.actualTotalArea"
                        v-model="scope.row.settlePieceArea"
                        :min="0"
                        :step="0.00001"
                        :precision="5"
                        style="width: 120px"
                        placeholder="自动计算"
                        :disabled="true"
                        style="width: 100%"
                        placeholder="请输入"
                        clearable
                        @change="() => handleInlineSettleAreaChange(scope.row)"
                     />
                     <span v-else>{{ scope.row.actualTotalArea ?? "" }}</span>
                     <span v-else>{{ scope.row.settlePieceArea ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="数量" prop="quantity" min-width="90">
               <el-table-column label="数量" prop="quantity" min-width="150">
                  <template #default="scope">
                     <el-input-number
                        v-if="scope.row.__editing"
@@ -411,12 +435,27 @@
                        :step="0.1"
                        :min="0"
                        :precision="2"
                        style="width: 110px"
                        style="width: 100%"
                        placeholder="请输入"
                        clearable
                        @change="() => handleInlineQuantityChange(scope.row)"
                        @input="() => handleInlineQuantityChange(scope.row)"
                     />
                     <span v-else>{{ scope.row.quantity ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="面积(m²)" prop="actualTotalArea" min-width="160">
                  <template #default="scope">
                     <el-input-number
                        v-if="scope.row.__editing"
                        v-model="scope.row.actualTotalArea"
                        :min="0"
                        :step="0.00001"
                        :precision="5"
                        style="width: 100%"
                        placeholder="自动计算"
                     />
                     <span v-else>{{ scope.row.actualTotalArea ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" min-width="140">
@@ -426,23 +465,24 @@
                        :step="0.01"
                        :min="0"
                        :precision="2"
                        style="width: 120px"
                        style="width: 100%"
                        v-model="scope.row.taxInclusiveUnitPrice"
                        placeholder="请输入"
                        clearable
                        @change="() => handleInlineUnitPriceChange(scope.row)"
                        @input="() => handleInlineUnitPriceChange(scope.row)"
                     />
                     <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveUnitPrice ?? 0) }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="税率(%)" prop="taxRate" min-width="90">
               <el-table-column label="税率(%)" prop="taxRate" min-width="120">
                  <template #default="scope">
                     <el-select
                        v-if="scope.row.__editing"
                        v-model="scope.row.taxRate"
                        placeholder="请选择"
                        clearable
                        style="width: 90px"
                        style="width: 100%"
                        @change="() => handleInlineTaxRateChange(scope.row)"
                     >
                        <el-option label="1" value="1" />
@@ -454,8 +494,8 @@
                     <span v-else>{{ scope.row.taxRate ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
               <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
               <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber"  min-width="120"/>
               <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber"  min-width="120"/>
               <el-table-column label="发票类型" prop="invoiceType" min-width="120">
                  <template #default="scope">
                     <el-select
@@ -463,7 +503,7 @@
                        v-model="scope.row.invoiceType"
                        placeholder="请选择"
                        clearable
                        style="width: 120px"
                        style="width: 100%"
                     >
                        <el-option label="增普票" value="增普票" />
                        <el-option label="增专票" value="增专票" />
@@ -471,22 +511,7 @@
                     <span v-else>{{ scope.row.invoiceType ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="结算单片面积(㎡)" prop="settlePieceArea" min-width="140">
                  <template #default="scope">
                     <el-input-number
                        v-if="scope.row.__editing"
                        v-model="scope.row.settlePieceArea"
                        :min="0"
                        :step="0.00001"
                        :precision="5"
                        style="width: 140px"
                        placeholder="请输入"
                        clearable
                        @change="() => handleInlineSettleAreaChange(scope.row)"
                     />
                     <span v-else>{{ scope.row.settlePieceArea ?? "" }}</span>
                  </template>
               </el-table-column>
               <el-table-column label="加工要求" prop="processRequirement" min-width="160" show-overflow-tooltip>
                  <template #default="scope">
                     <el-input
@@ -494,7 +519,7 @@
                        v-model="scope.row.processRequirement"
                        placeholder="请输入"
                        clearable
                        style="width: 160px"
                        style="width: 100%"
                     />
                     <span v-else>{{ scope.row.processRequirement ?? "" }}</span>
                  </template>
@@ -506,7 +531,7 @@
                        v-model="scope.row.remark"
                        placeholder="请输入"
                        clearable
                        style="width: 140px"
                        style="width: 100%"
                     />
                     <span v-else>{{ scope.row.remark ?? "" }}</span>
                  </template>
@@ -518,7 +543,7 @@
                        v-model="scope.row.floorCode"
                        placeholder="请输入"
                        clearable
                        style="width: 140px"
                        style="width: 100%"
                     />
                     <span v-else>{{ scope.row.floorCode ?? "" }}</span>
                  </template>
@@ -530,7 +555,7 @@
                        v-model="scope.row.heavyBox"
                        placeholder="请输入"
                        clearable
                        style="width: 110px"
                        style="width: 100%"
                     />
                     <span v-else>{{ scope.row.heavyBox ?? "" }}</span>
                  </template>
@@ -541,10 +566,11 @@
                        <el-button link type="primary" size="small" @click="saveProductInline(scope.row, scope.$index)">保存</el-button>
                        <el-button link type="danger" size="small" @click="cancelProductInline(scope.row, scope.$index)">取消</el-button>
                        <el-popover
                           :width="420"
                           :width="560"
                           trigger="click"
                           :hide-after="0"
                           v-model:visible="scope.row.__otherAmountPopoverVisible"
                           :visible="scope.row.__otherAmountPopoverVisible"
                           @update:visible="(val) => handleOtherAmountPopoverVisibleChange(scope.row, val)"
                        >
                           <template #reference>
                              <el-button
@@ -565,14 +591,50 @@
                                 新增
                              </el-button>
                           </div>
                           <div
                              v-if="scope.row.__inlineOtherAmountAdding"
                              style="display:flex; flex-direction:column; gap: 8px; margin-bottom: 10px;"
                              @click.stop
                           >
                              <el-select
                                 v-model="scope.row.__inlineOtherAmountAddId"
                                 filterable
                                 clearable
                                 placeholder="请选择其他金额项目"
                                 style="width: 100%;"
                              >
                                 <el-option
                                    v-for="item in otherAmountSelectOptions"
                                    :key="item.id"
                                    :label="item.processName"
                                    :value="item.id"
                                 />
                              </el-select>
                              <div style="display:flex; justify-content:flex-end; gap: 8px;">
                                 <el-button
                                    size="small"
                                    @click="scope.row.__inlineOtherAmountAdding = false; scope.row.__inlineOtherAmountAddId = null"
                                 >
                                    取消
                                 </el-button>
                                 <el-button
                                    type="primary"
                                    size="small"
                                    :disabled="scope.row.__inlineOtherAmountAddId === null || scope.row.__inlineOtherAmountAddId === undefined || scope.row.__inlineOtherAmountAddId === ''"
                                    @click="confirmAddOtherAmountForRow(scope.row)"
                                 >
                                    确认添加
                                 </el-button>
                              </div>
                           </div>
                           <div v-if="Array.isArray(scope.row.salesProductProcessList) && scope.row.salesProductProcessList.length > 0"
                              style="display:flex; flex-direction:column; gap: 8px;"
                              style="display:flex; flex-wrap:wrap; gap: 8px;"
                           >
                              <div
                                 v-for="(item, idx) in scope.row.salesProductProcessList"
                                 :key="String(item.id) + '_' + idx"
                                 style="display:flex; align-items:center; gap: 8px;"
                                 style="display:flex; align-items:center; gap: 8px; flex: 0 0 calc(50% - 4px); max-width: calc(50% - 4px);"
                              >
                                 <el-tag type="info" style="max-width: 170px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
                                    {{ item.processName }}
@@ -608,10 +670,11 @@
                           编辑
                        </el-button>
                        <el-popover
                           :width="420"
                           :width="560"
                           trigger="click"
                           :hide-after="0"
                           v-model:visible="scope.row.__otherAmountPopoverVisible"
                           :visible="scope.row.__otherAmountPopoverVisible"
                           @update:visible="(val) => handleOtherAmountPopoverVisibleChange(scope.row, val)"
                        >
                           <template #reference>
                              <el-button
@@ -639,14 +702,52 @@
                                 新增
                              </el-button>
                           </div>
                           <div
                              v-if="scope.row.__inlineOtherAmountAdding"
                              style="display:flex; flex-direction:column; gap: 8px; margin-bottom: 10px;"
                              @click.stop
                           >
                              <el-select
                                 v-model="scope.row.__inlineOtherAmountAddId"
                                 filterable
                                 clearable
                                 placeholder="请选择其他金额项目"
                                 style="width: 100%;"
                                 :disabled="isProductShipped(scope.row)"
                              >
                                 <el-option
                                    v-for="item in otherAmountSelectOptions"
                                    :key="item.id"
                                    :label="item.processName"
                                    :value="item.id"
                                 />
                              </el-select>
                              <div style="display:flex; justify-content:flex-end; gap: 8px;">
                                 <el-button
                                    size="small"
                                    :disabled="isProductShipped(scope.row)"
                                    @click="scope.row.__inlineOtherAmountAdding = false; scope.row.__inlineOtherAmountAddId = null"
                                 >
                                    取消
                                 </el-button>
                                 <el-button
                                    type="primary"
                                    size="small"
                                    :disabled="isProductShipped(scope.row) || scope.row.__inlineOtherAmountAddId === null || scope.row.__inlineOtherAmountAddId === undefined || scope.row.__inlineOtherAmountAddId === ''"
                                    @click="confirmAddOtherAmountForRow(scope.row)"
                                 >
                                    确认添加
                                 </el-button>
                              </div>
                           </div>
                           <div v-if="Array.isArray(scope.row.salesProductProcessList) && scope.row.salesProductProcessList.length > 0"
                              style="display:flex; flex-direction:column; gap: 8px;"
                              style="display:flex; flex-wrap:wrap; gap: 8px;"
                           >
                              <div
                                 v-for="(item, idx) in scope.row.salesProductProcessList"
                                 :key="String(item.id) + '_' + idx"
                                 style="display:flex; align-items:center; gap: 8px;"
                                 style="display:flex; align-items:center; gap: 8px; flex: 0 0 calc(50% - 4px); max-width: calc(50% - 4px);"
                              >
                                 <el-tag type="info" style="max-width: 170px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
                                    {{ item.processName }}
@@ -1278,7 +1379,7 @@
<script setup>
import { getToken } from "@/utils/auth";
import pagination from "@/components/PIMTable/Pagination.vue";
import {onMounted, ref, getCurrentInstance, watch} from "vue";
import {onMounted, ref, getCurrentInstance, watch, nextTick} from "vue";
import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
import { ElMessageBox, ElMessage } from "element-plus";
import { ArrowDown } from "@element-plus/icons-vue";
@@ -1308,6 +1409,7 @@
   getSalesOrder,
   getSalesInvoices,
   getSalesLabel,
   salesStock,
} from "@/api/salesManagement/salesLedger.js";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import useFormData from "@/hooks/useFormData.js";
@@ -1356,6 +1458,7 @@
      entryDateStart: undefined,
      entryDateEnd: undefined,
      deliveryStatus: undefined, // 发货状态:1未发货 2审批中 3审批失败 4已发货
      stockStatus: undefined, // 入库状态:0未入库 1已入库
   },
   form: {
      salesContractNo: "",
@@ -1436,6 +1539,8 @@
   if (!row || typeof row !== "object") return;
   if (!Array.isArray(row.salesProductProcessList)) row.salesProductProcessList = [];
   if (row.__otherAmountPopoverVisible === undefined || row.__otherAmountPopoverVisible === null) row.__otherAmountPopoverVisible = false;
   if (row.__inlineOtherAmountAdding === undefined || row.__inlineOtherAmountAdding === null) row.__inlineOtherAmountAdding = false;
   if (row.__inlineOtherAmountAddId === undefined) row.__inlineOtherAmountAddId = null;
   if (row.width === undefined || row.width === null) row.width = 0;
   if (row.height === undefined || row.height === null) row.height = 0;
   if (row.perimeter === undefined || row.perimeter === null) row.perimeter = 0;
@@ -1461,10 +1566,16 @@
   editingProductRow.value = null;
};
const hasEditingProductRow = () => {
   return (productData.value || []).some((r) => r && r.__editing);
};
const addProductInline = async () => {
   if (operationType.value === "view") return;
   // 已有行在编辑时,先取消其编辑状态,避免混乱
   stopOtherEditingRows();
   if (hasEditingProductRow()) {
      proxy.$modal.msgWarning("请先保存或取消当前编辑行");
      return;
   }
   await getProductOptions();
   await fetchOtherAmountSelectOptions(true);
   const row = {
@@ -1591,6 +1702,9 @@
   // 提交前兜底计算一次(沿用原逻辑)
   recalcAreaTotals();
   // 提交兜底:税率/数量未填时按数字 0 传递
   row.taxRate = Number(row.taxRate ?? 0) || 0;
   row.quantity = Number(row.quantity ?? 0) || 0;
   // 规范化其他金额提交结构
   row.salesProductProcessList = (Array.isArray(row.salesProductProcessList) ? row.salesProductProcessList : [])
@@ -1655,11 +1769,43 @@
   }
   ensureProductRowDefaults(row);
   productForm.value = row;
   otherAmountAddTargetRow.value = row;
   await fetchOtherAmountSelectOptions(true);
   mergeOtherAmountOptionsBySelection(row.salesProductProcessList);
   row.salesProductProcessList = fillOtherAmountProcessName(row.salesProductProcessList);
   // 只做数据准备与打开浮层(新增由浮层内按钮触发)
   row.__otherAmountPopoverVisible = true;
};
const keepOtherAmountPopoverOpenKey = ref(null);
const keepOtherAmountPopoverOpenUntil = ref(0);
const getOtherAmountRowKey = (row) => String(row?.__tempKey ?? row?.id ?? "");
const lockOtherAmountPopoverOpen = (row, durationMs = 1200) => {
   const key = getOtherAmountRowKey(row);
   if (!key) return;
   keepOtherAmountPopoverOpenKey.value = key;
   keepOtherAmountPopoverOpenUntil.value = Date.now() + durationMs;
};
const handleOtherAmountPopoverVisibleChange = (row, visible) => {
   if (!row) return;
   if (visible) {
      row.__otherAmountPopoverVisible = true;
      return;
   }
   if (row.__inlineOtherAmountAdding) {
      row.__otherAmountPopoverVisible = true;
      return;
   }
   const key = getOtherAmountRowKey(row);
   const shouldKeepOpen = Boolean(
      key &&
      keepOtherAmountPopoverOpenKey.value === key &&
      Date.now() < keepOtherAmountPopoverOpenUntil.value
   );
   row.__otherAmountPopoverVisible = shouldKeepOpen;
};
const startAddOtherAmountForRow = async (row) => {
@@ -1674,7 +1820,36 @@
   await fetchOtherAmountSelectOptions(true);
   mergeOtherAmountOptionsBySelection(row.salesProductProcessList);
   row.salesProductProcessList = fillOtherAmountProcessName(row.salesProductProcessList);
   startAddOtherAmount();
   row.__inlineOtherAmountAddId = null;
   row.__inlineOtherAmountAdding = true;
   row.__otherAmountPopoverVisible = true;
};
const confirmAddOtherAmountForRow = (row) => {
   if (!row) return;
   ensureProductRowDefaults(row);
   productForm.value = row;
   const selectedId = row.__inlineOtherAmountAddId;
   if (selectedId === null || selectedId === undefined || selectedId === "") return;
   const opt = otherAmountSelectOptions.value.find((o) => String(o.id) === String(selectedId));
   if (!opt) return;
   const exists = (row.salesProductProcessList ?? []).some(
      (it) => String(it?.id) === String(opt.id)
   );
   if (exists) {
      proxy.$modal.msgWarning("该其他金额项目已添加");
      return;
   }
   row.salesProductProcessList.push({
      id: opt.id,
      processName: opt.processName,
      unitPrice: opt.unitPrice ?? 0,
      quantity: 0,
   });
   row.__inlineOtherAmountAddId = null;
   row.__inlineOtherAmountAdding = false;
   row.__otherAmountPopoverVisible = true;
   calculateFromUnitPrice(true);
};
const removeOtherAmountAtForRow = (row, index) => {
@@ -1892,6 +2067,8 @@
// 其他金额:点击“新增”后在弹窗里选择一个项目
const otherAmountAddDialogVisible = ref(false);
const otherAmountAddId = ref(null);
const otherAmountAddTargetRow = ref(null);
const otherAmountAddTargetRowKey = ref(null);
const startAddOtherAmount = () => {
   if (operationType.value === "view") return;
@@ -1906,6 +2083,10 @@
const cancelAddOtherAmount = () => {
   otherAmountAddDialogVisible.value = false;
   otherAmountAddId.value = null;
   otherAmountAddTargetRow.value = null;
   otherAmountAddTargetRowKey.value = null;
   keepOtherAmountPopoverOpenKey.value = null;
   keepOtherAmountPopoverOpenUntil.value = 0;
};
const handleOtherAmountSelected = (id) => {
@@ -1930,9 +2111,30 @@
   });
   calculateFromUnitPrice(true);
   // 选择完成后关闭弹窗,下一次可再次点击“新增”继续添加
   // 选择完成后关闭“新增其他金额”弹窗,并保持行内“其他金额”弹层开启,便于直接填写数量
   otherAmountAddDialogVisible.value = false;
   otherAmountAddId.value = null;
   const reopenOtherAmountPopover = () => {
      let targetRow = otherAmountAddTargetRow.value;
      const rowKey = otherAmountAddTargetRowKey.value;
      if (rowKey) {
         const matchedRow = (productData.value || []).find(
            (it) => String(it?.__tempKey ?? it?.id ?? "") === rowKey
         );
         if (matchedRow) targetRow = matchedRow;
      }
      if (targetRow && typeof targetRow === "object") {
         lockOtherAmountPopoverOpen(targetRow, 1500);
         targetRow.__otherAmountPopoverVisible = true;
      }
   };
   nextTick(() => {
      reopenOtherAmountPopover();
      setTimeout(reopenOtherAmountPopover, 0);
      setTimeout(reopenOtherAmountPopover, 80);
   });
   otherAmountAddTargetRow.value = null;
   otherAmountAddTargetRowKey.value = null;
};
const confirmAddOtherAmount = () => {
@@ -2066,6 +2268,43 @@
      .catch(() => {
         tableLoading.value = false;
      });
};
// 入库(销售台账 -> 入库状态)
const handleSalesStock = async () => {
   if (selectedRows.value.length !== 1) {
      ElMessage.warning("请勾选一条台账数据进行入库");
      return;
   }
   const row = selectedRows.value[0] || {};
   const id = row?.id;
   if (!id) {
      ElMessage.warning("所选数据缺少id,无法入库");
      return;
   }
   if (Number(row.stockStatus) === 1) {
      ElMessage.info("该台账已入库,无需重复操作");
      return;
   }
   try {
      await ElMessageBox.confirm("确认对所选台账执行入库?", "提示", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
         type: "warning",
      });
   } catch {
      return;
   }
   proxy?.$modal?.loading?.("正在入库,请稍候...");
   try {
      await salesStock({ id });
      proxy?.$modal?.msgSuccess?.("入库成功");
      await getList();
   } catch (e) {
      proxy?.$modal?.msgError?.("入库失败,请稍后重试");
   } finally {
      proxy?.$modal?.closeLoading?.();
   }
};
// 打开“工艺路线配置”选择弹窗(必须显式选择)
@@ -2213,15 +2452,18 @@
   }
   return null; // 没有找到节点,返回null
};
function convertIdToValue(data) {
function convertIdToValue(data, level = 0) {
   return data.map((item) => {
      const { id, children, ...rest } = item;
      const hasChildren = Array.isArray(children) && children.length > 0;
      const newItem = {
         ...rest,
         value: id, // 将 id 改为 value
         // 仅允许叶子节点被选择(有子节点的分类节点统一禁用)
         disabled: Boolean(rest?.disabled) || hasChildren,
      };
      if (children && children.length > 0) {
         newItem.children = convertIdToValue(children);
      if (hasChildren) {
         newItem.children = convertIdToValue(children, level + 1);
      }
      
      return newItem;
@@ -2505,6 +2747,8 @@
            const cleanedProducts = (productData.value || []).map((p) => {
               if (!p || typeof p !== "object") return p;
               const { __editing, __isNew, __backup, __productCategoryId, __tempKey, __otherAmountPopoverVisible, ...rest } = p;
               rest.taxRate = Number(rest.taxRate ?? 0) || 0;
               rest.quantity = Number(rest.quantity ?? 0) || 0;
               return rest;
            });
            form.value.productData = proxy.HaveJson(cleanedProducts);
@@ -2625,6 +2869,9 @@
         // 面积/总计字段在提交前兜底计算一次
         recalcAreaTotals();
         // 提交兜底:税率/数量未填时按数字 0 传递
         productForm.value.taxRate = Number(productForm.value.taxRate ?? 0) || 0;
         productForm.value.quantity = Number(productForm.value.quantity ?? 0) || 0;
         // 其他金额只提交 {id, processName, quantity}(后端字段:salesProductProcessList)
         productForm.value.salesProductProcessList = (Array.isArray(productForm.value.salesProductProcessList)
         ? productForm.value.salesProductProcessList
@@ -3060,10 +3307,10 @@
// 根据不含税总价计算含税单价和数量
const calculateFromExclusiveTotalPrice = () => {
   if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
   }
   // if (!productForm.value.taxRate) {
   //    proxy.$modal.msgWarning("请先选择税率");
   //    return;
   // }
   if (isCalculating.value) return;
   
   const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice);
@@ -3093,10 +3340,10 @@
// 根据数量变化计算总价
const calculateFromQuantity = () => {
   if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
   }
   // if (!productForm.value.taxRate) {
   //    proxy.$modal.msgWarning("请先选择税率");
   //    return;
   // }
   if (isCalculating.value) return;
   const quantity = parseFloat(productForm.value.quantity);
@@ -3130,10 +3377,10 @@
// 根据含税单价变化计算总价
const calculateFromUnitPrice = (silent = false) => {
   if (!productForm.value.taxRate) {
      if (!silent) proxy.$modal.msgWarning("请先选择税率");
      return;
   }
   // if (!productForm.value.taxRate) {
   //    if (!silent) proxy.$modal.msgWarning("请先选择税率");
   //    return;
   // }
   if (isCalculating.value) return;
   const quantity = parseFloat(productForm.value.quantity);
@@ -3167,10 +3414,10 @@
// 根据税率变化计算不含税总价
const calculateFromTaxRate = () => {
   if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
   }
   // if (!productForm.value.taxRate) {
   //    proxy.$modal.msgWarning("请先选择税率");
   //    return;
   // }
   if (isCalculating.value) return;
   
   const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);