zouyu
91 分钟以前 01a6c87b789624165373efa455e0520a613a6114
src/views/salesManagement/salesLedger/index.vue
@@ -1,42 +1,47 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <el-form :model="searchForm"
               :inline="true">
      <el-form :model="searchForm" :inline="true">
        <el-form-item label="客户名称:">
          <el-input v-model="searchForm.customerName"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    @change="handleQuery"/>
          <el-input
            v-model="searchForm.customerName"
            placeholder="请输入"
            clearable
            prefix-icon="Search"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="销售合同号:">
          <el-input v-model="searchForm.salesContractNo"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    @change="handleQuery"/>
          <el-input
            v-model="searchForm.salesContractNo"
            placeholder="请输入"
            clearable
            prefix-icon="Search"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="项目名称:">
          <el-input v-model="searchForm.projectName"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    @change="handleQuery"/>
          <el-input
            v-model="searchForm.projectName"
            placeholder="请输入"
            clearable
            prefix-icon="Search"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="录入日期:">
          <el-date-picker v-model="searchForm.entryDate"
                          value-format="YYYY-MM-DD"
                          format="YYYY-MM-DD"
                          type="daterange"
                          placeholder="请选择"
                          clearable
                          @change="changeDaterange"/>
          <el-date-picker
            v-model="searchForm.entryDate"
            value-format="YYYY-MM-DD"
            format="YYYY-MM-DD"
            type="daterange"
            placeholder="请选择"
            clearable
            @change="changeDaterange"
          />
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery"> 搜索
          </el-button>
          <el-button type="primary" @click="handleQuery"> 搜索 </el-button>
        </el-form-item>
      </el-form>
    </div>
@@ -44,141 +49,137 @@
      <div class="actions">
        <div></div>
        <div>
          <el-button type="primary"
                     @click="openForm('add')">
          <el-button type="primary" @click="openForm('add')">
            新增台账
          </el-button>
          <el-button type="primary"
                     plain
                     @click="handleImport">导入
          <el-button type="primary" plain @click="handleImport"
            >导入
          </el-button>
          <el-button @click="handleOut">导出</el-button>
          <el-button type="danger"
                     plain
                     @click="handleDelete">删除
          </el-button>
          <el-button type="primary"
                     plain
                     @click="handlePrint">打印
          </el-button>
          <el-button type="danger" plain @click="handleDelete">删除 </el-button>
          <el-button type="primary" plain @click="handlePrint">打印 </el-button>
        </div>
      </div>
      <el-table :data="tableData"
                border
                v-loading="tableLoading"
                @selection-change="handleSelectionChange"
                :expand-row-keys="expandedRowKeys"
                :row-key="(row) => row.id"
                :row-class-name="tableRowClassName"
                show-summary
                style="width: 100%"
                :summary-method="summarizeMainTable"
                @expand-change="expandChange"
                height="calc(100vh - 18.5em)">
        <el-table-column align="center"
                         type="selection"
                         width="55"
                         fixed="left"/>
        <el-table-column type="expand"
                         width="60"
                         fixed="left">
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
        @selection-change="handleSelectionChange"
        :expand-row-keys="expandedRowKeys"
        :row-key="(row) => row.id"
        :row-class-name="tableRowClassName"
        show-summary
        style="width: 100%"
        :summary-method="summarizeMainTable"
        @expand-change="expandChange"
        height="calc(100vh - 18.5em)"
      >
        <el-table-column
          align="center"
          type="selection"
          width="55"
          fixed="left"
        />
        <el-table-column type="expand" width="60" fixed="left">
          <template #default="props">
            <el-table :data="props.row.children"
                      border
                      show-summary
                      :summary-method="(param) => summarizeChildrenTable(param, props.row)">
              <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="产品状态"
                               width="100px"
                               align="center">
            <el-table
              :data="props.row.children"
              border
              show-summary
              :summary-method="
                (param) => summarizeChildrenTable(param, props.row)
              "
            >
              <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="产品状态" width="100px" align="center">
                <template #default="scope">
                  <el-tag
                      v-if="scope.row.approveStatus === 1 && scope.row.noQuantity !== 0"
                      type="success">充足
                  <el-tag v-if="scope.row.approveStatus === 1" type="success"
                    >充足
                  </el-tag>
                  <el-tag
                      v-else-if="scope.row.approveStatus === 0 && scope.row.noQuantity === 0"
                      type="success">已出库
                    v-else-if="
                      scope.row.approveStatus === 0 &&
                      scope.row.noQuantity === 0
                    "
                    type="success"
                    >已出库
                  </el-tag>
                  <el-tag v-else
                          type="danger">不足
                  </el-tag>
                  <el-tag v-else type="danger">不足 </el-tag>
                </template>
              </el-table-column>
              <el-table-column label="发货状态"
                               width="140"
                               align="center">
              <el-table-column label="发货状态" width="140" align="center">
                <template #default="scope">
                  <el-tag :type="getShippingStatusType(scope.row)"
                          size="small">
                  <el-tag :type="getShippingStatusType(scope.row)" size="small">
                    {{ getShippingStatusText(scope.row) }}
                  </el-tag>
                </template>
              </el-table-column>
              <el-table-column label="快递公司"
                               prop="expressCompany"
                               show-overflow-tooltip/>
              <el-table-column label="快递单号"
                               prop="expressNumber"
                               show-overflow-tooltip/>
              <el-table-column label="发货车牌"
                               minWidth="100px"
                               align="center">
              <el-table-column label="审批中数量" width="120" align="center">
                <template #default="scope">
                  <span>{{ scope.row.pendingApprovalQuantity || 0 }}</span>
                </template>
              </el-table-column>
              <el-table-column
                label="快递公司"
                prop="expressCompany"
                show-overflow-tooltip
              />
              <el-table-column
                label="快递单号"
                prop="expressNumber"
                show-overflow-tooltip
              />
              <el-table-column label="发货车牌" minWidth="100px" align="center">
                <template #default="scope">
                  <div>
                    <el-tag type="success"
                            v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}
                    <el-tag type="success" v-if="scope.row.shippingCarNumber"
                      >{{ scope.row.shippingCarNumber }}
                    </el-tag>
                    <el-tag v-else
                            type="info">-
                    </el-tag>
                    <el-tag v-else type="info">- </el-tag>
                  </div>
                </template>
              </el-table-column>
              <el-table-column label="发货日期"
                               minWidth="100px"
                               align="center">
              <el-table-column label="发货日期" minWidth="100px" align="center">
                <template #default="scope">
                  <div>
                    <div v-if="scope.row.shippingDate">{{ scope.row.shippingDate }}</div>
                    <el-tag v-else
                            type="info">-
                    </el-tag>
                    <div v-if="scope.row.shippingDate">
                      {{ scope.row.shippingDate }}
                    </div>
                    <el-tag v-else type="info">- </el-tag>
                  </div>
                </template>
              </el-table-column>
              <el-table-column label="数量"
                               prop="quantity"/>
              <el-table-column label="待发货数量"
                               prop="noQuantity"/>
              <el-table-column label="税率(%)"
                               prop="taxRate"/>
              <el-table-column label="含税单价(元)"
                               prop="taxInclusiveUnitPrice"
                               :formatter="sensitiveAmountFormatter"/>
              <el-table-column label="含税总价(元)"
                               prop="taxInclusiveTotalPrice"
                               :formatter="sensitiveAmountFormatter"/>
              <el-table-column label="不含税总价(元)"
                               prop="taxExclusiveTotalPrice"
                               :formatter="sensitiveAmountFormatter"/>
              <el-table-column label="数量" prop="quantity" />
              <el-table-column label="退货数量" prop="returnQuantity" />
              <el-table-column label="待发货数量" prop="noQuantity" />
              <el-table-column label="税率(%)" prop="taxRate" />
              <el-table-column
                label="含税单价(元)"
                prop="taxInclusiveUnitPrice"
                :formatter="sensitiveAmountFormatter"
              />
              <el-table-column
                label="含税总价(元)"
                prop="taxInclusiveTotalPrice"
                :formatter="sensitiveAmountFormatter"
              />
              <el-table-column
                label="不含税总价(元)"
                prop="taxExclusiveTotalPrice"
                :formatter="sensitiveAmountFormatter"
              />
              <!--操作-->
              <el-table-column Width="60px"
                               label="操作"
                               align="center">
              <el-table-column Width="60px" label="操作" align="center">
                <template #default="scope">
                  <el-button link
                             type="primary"
                             :disabled="!canShip(scope.row)"
                             @click="openDeliveryForm(scope.row)">
                  <el-button
                    link
                    type="primary"
                    :disabled="!canShip(scope.row)"
                    @click="openDeliveryForm(scope.row)"
                  >
                    发货
                  </el-button>
                </template>
@@ -186,141 +187,205 @@
            </el-table>
          </template>
        </el-table-column>
        <el-table-column align="center"
                         label="序号"
                         type="index"
                         width="60"/>
        <el-table-column label="销售合同号"
                         prop="salesContractNo"
                         width="180"
                         show-overflow-tooltip/>
        <el-table-column label="客户名称"
                         prop="customerName"
                         width="300"
                         show-overflow-tooltip/>
        <el-table-column label="业务员"
                         prop="salesman"
                         width="100"
                         show-overflow-tooltip/>
        <el-table-column label="项目名称"
                         prop="projectName"
                         width="180"
                         show-overflow-tooltip/>
        <el-table-column label="付款方式"
                         prop="paymentMethod"
                         show-overflow-tooltip/>
        <el-table-column label="合同金额(元)"
                         prop="contractAmount"
                         width="220"
                         show-overflow-tooltip
                         :formatter="formattedNumber"/>
        <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/>
        <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 align="center" label="序号" type="index" width="60" />
        <el-table-column
          label="销售合同号"
          prop="salesContractNo"
          width="180"
          show-overflow-tooltip
        />
        <el-table-column
          label="客户名称"
          prop="customerName"
          width="300"
          show-overflow-tooltip
        />
        <el-table-column
          label="业务员"
          prop="salesman"
          width="100"
          show-overflow-tooltip
        />
        <el-table-column
          label="项目名称"
          prop="projectName"
          width="180"
          show-overflow-tooltip
        />
        <el-table-column
          label="付款方式"
          prop="paymentMethod"
          show-overflow-tooltip
        />
        <el-table-column
          label="合同金额(元)"
          prop="contractAmount"
          width="220"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
        <el-table-column
          label="实际合同金额(元)"
          prop="netContractAmount"
          width="220"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
        <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
        />
        <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="220" align="center">
          <template #default="scope">
            <el-button link
                       type="primary"
                       @click="openForm('edit', scope.row)"
                       :disabled="!scope.row.isEdit || scope.row.hasProductionRecord || !canEditLedger(scope.row)">编辑
            <el-button link type="primary" @click="openForm('view', scope.row)"
              >详情
            </el-button>
            <el-button link
                       type="primary"
                       @click="openFileDialog(scope.row)">附件
            <el-button
              link
              type="primary"
              @click="openForm('edit', scope.row)"
              :disabled="
                !scope.row.isEdit ||
                scope.row.hasProductionRecord ||
                !canEditLedger(scope.row)
              "
              >编辑
            </el-button>
            <el-button link type="primary" @click="openFileDialog(scope.row)"
              >附件
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0"
                  :total="total"
                  layout="total, sizes, prev, pager, next, jumper"
                  :page="page.current"
                  :limit="page.size"
                  @pagination="paginationChange"/>
      <pagination
        v-show="total > 0"
        :total="total"
        layout="total, sizes, prev, pager, next, jumper"
        :page="page.current"
        :limit="page.size"
        @pagination="paginationChange"
      />
    </div>
    <FormDialog v-model="dialogFormVisible"
                :title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'"
                :width="'70%'"
                :operation-type="operationType"
                @close="closeDia"
                @confirm="submitForm"
                @cancel="closeDia">
      <el-form :model="form"
               label-width="140px"
               label-position="top"
               :rules="rules"
               ref="formRef">
    <FormDialog
      v-model="dialogFormVisible"
      :title="
        operationType === 'add'
          ? '新增销售台账页面'
          : operationType === 'edit'
          ? '编辑销售台账页面'
          : '销售台账详情'
      "
      :width="'70%'"
      :operation-type="operationType"
      @close="closeDia"
      @confirm="submitForm"
      @cancel="closeDia"
    >
      <el-form
        :model="form"
        label-width="140px"
        label-position="top"
        :rules="rules"
        ref="formRef"
      >
        <!-- 报价单导入入口:放在表单顶部,选择后反显客户/业务员等 -->
        <el-row v-if="operationType === 'add'"
                style="margin-bottom: 10px;">
          <el-col :span="24"
                  style="text-align: right;">
            <el-button type="primary"
                       plain
                       @click="openQuotationDialog">
        <el-row v-if="operationType === 'add'" style="margin-bottom: 10px">
          <el-col :span="24" style="text-align: right">
            <el-button type="primary" plain @click="openQuotationDialog">
              从销售报价导入
            </el-button>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="销售合同号:"
                          prop="salesContractNo">
              <el-input v-model="form.salesContractNo"
                        placeholder="自动生成"
                        clearable
                        disabled/>
            <el-form-item label="销售合同号:" prop="salesContractNo">
              <div
                style="
                  display: flex;
                  align-items: center;
                  gap: 12px;
                  width: 100%;
                "
              >
                <el-checkbox
                  v-model="form.autoGenerateContractNo"
                  v-if="operationType === 'add'"
                  >自动生成
                </el-checkbox>
                <el-input
                  v-model="form.salesContractNo"
                  :placeholder="
                    form.autoGenerateContractNo ? '保存后自动生成' : '请输入'
                  "
                  clearable
                  :disabled="
                    form.autoGenerateContractNo || operationType === 'view'
                  "
                />
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="业务员:"
                          prop="salesman">
              <el-select v-model="form.salesman"
                         placeholder="请选择"
                         clearable
                         :disabled="operationType === 'view'"
                         filterable>
                <el-option v-for="item in userList"
                           :key="item.nickName"
                           :label="item.nickName"
                           :value="item.nickName"/>
            <el-form-item label="业务员:" prop="salesman">
              <el-select
                v-model="form.salesman"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'view'"
                filterable
              >
                <el-option
                  v-for="item in userList"
                  :key="item.nickName"
                  :label="item.nickName"
                  :value="item.nickName"
                />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="客户名称:"
                          prop="customerId">
              <el-select v-model="form.customerId"
                         placeholder="请选择"
                         clearable
                         :disabled="operationType === 'view'"
                         filterable>
                <el-option v-for="item in customerOption"
                           :key="item.id"
                           :label="item.customerName"
                           :value="item.id">
            <el-form-item label="客户名称:" prop="customerId">
              <el-select
                v-model="form.customerId"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'view'"
                filterable
              >
                <el-option
                  v-for="item in customerOption"
                  :key="item.id"
                  :label="item.customerName"
                  :value="item.id"
                >
                  {{
                    item.customerName + "——" + item.taxpayerIdentificationNumber
                  }}
@@ -329,397 +394,453 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="项目名称:"
                          prop="projectName">
              <el-input v-model="form.projectName"
                        placeholder="请输入"
                        clearable
                        :disabled="operationType === 'view'"/>
            <el-form-item label="项目名称:" prop="projectName">
              <el-input
                v-model="form.projectName"
                placeholder="请输入"
                clearable
                :disabled="operationType === 'view'"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="签订日期:"
                          prop="executionDate">
              <el-date-picker style="width: 100%"
                              v-model="form.executionDate"
                              value-format="YYYY-MM-DD"
                              format="YYYY-MM-DD"
                              type="date"
                              placeholder="请选择"
                              clearable
                              :disabled="operationType === 'view'"/>
            <el-form-item label="签订日期:" prop="executionDate">
              <el-date-picker
                style="width: 100%"
                v-model="form.executionDate"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                type="date"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'view'"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="付款方式">
              <el-input v-model="form.paymentMethod"
                        placeholder="请输入"
                        clearable
                        :disabled="operationType === 'view'"/>
              <el-input
                v-model="form.paymentMethod"
                placeholder="请输入"
                clearable
                :disabled="operationType === 'view'"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="录入人:"
                          prop="entryPerson">
              <el-select v-model="form.entryPerson"
                         filterable
                         default-first-option
                         :reserve-keyword="false"
                         placeholder="请选择"
                         clearable
                         @change="changs">
                <el-option v-for="item in userList"
                           :key="item.userId"
                           :label="item.nickName"
                           :value="item.userId"/>
            <el-form-item label="录入人:" prop="entryPerson">
              <el-select
                v-model="form.entryPerson"
                filterable
                default-first-option
                :reserve-keyword="false"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'view'"
                @change="changs"
              >
                <el-option
                  v-for="item in userList"
                  :key="item.userId"
                  :label="item.nickName"
                  :value="item.userId"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="录入日期:"
                          prop="entryDate">
              <el-date-picker style="width: 100%"
                              v-model="form.entryDate"
                              value-format="YYYY-MM-DD"
                              format="YYYY-MM-DD"
                              type="date"
                              placeholder="请选择"
                              clearable/>
            <el-form-item label="录入日期:" prop="entryDate">
              <el-date-picker
                style="width: 100%"
                v-model="form.entryDate"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                type="date"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'view'"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="交货日期:"
                          prop="entryDate">
              <el-date-picker style="width: 100%"
                              v-model="form.deliveryDate"
                              value-format="YYYY-MM-DD"
                              format="YYYY-MM-DD"
                              type="date"
                              placeholder="请选择"
                              clearable/>
            <el-form-item label="交货日期:" prop="entryDate">
              <el-date-picker
                style="width: 100%"
                v-model="form.deliveryDate"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                type="date"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'view'"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-form-item label="产品信息:"
                        prop="entryDate">
            <el-button v-if="operationType !== 'view'"
                       type="primary"
                       @click="openProductForm('add')">添加
          <el-form-item label="产品信息:" prop="entryDate">
            <el-button
              v-if="operationType !== 'view'"
              type="primary"
              @click="openProductForm('add')"
              >添加
            </el-button>
            <el-button v-if="operationType !== 'view'"
                       plain
                       type="danger"
                       @click="deleteProduct">删除
            <el-button
              v-if="operationType !== 'view'"
              plain
              type="danger"
              @click="deleteProduct"
              >删除
            </el-button>
          </el-form-item>
        </el-row>
        <el-table :data="productData"
                  border
                  @selection-change="productSelected"
                  show-summary
                  :summary-method="summarizeMainTable">
          <el-table-column align="center"
                           type="selection"
                           width="55"
                           v-if="operationType !== 'view'"
                           :selectable="(row) => !isProductShipped(row)"/>
          <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="quantity"/>
          <el-table-column label="税率(%)"
                           prop="taxRate"/>
          <el-table-column label="含税单价(元)"
                           prop="taxInclusiveUnitPrice"
                           :formatter="formattedNumber"/>
          <el-table-column label="含税总价(元)"
                           prop="taxInclusiveTotalPrice"
                           :formatter="formattedNumber"/>
          <el-table-column label="不含税总价(元)"
                           prop="taxExclusiveTotalPrice"
                           :formatter="formattedNumber"/>
          <el-table-column label="是否生产"
                           prop="isProduction"
                           width="150">
        <el-table
          :data="productData"
          border
          @selection-change="productSelected"
          show-summary
          :summary-method="summarizeMainTable"
        >
          <el-table-column
            align="center"
            type="selection"
            width="55"
            v-if="operationType !== 'view'"
            :selectable="(row) => !isProductShipped(row)"
          />
          <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="quantity" />
          <el-table-column label="税率(%)" prop="taxRate" />
          <el-table-column
            label="含税单价(元)"
            prop="taxInclusiveUnitPrice"
            :formatter="formattedNumber"
          />
          <el-table-column
            label="含税总价(元)"
            prop="taxInclusiveTotalPrice"
            :formatter="formattedNumber"
          />
          <el-table-column
            label="不含税总价(元)"
            prop="taxExclusiveTotalPrice"
            :formatter="formattedNumber"
          />
          <el-table-column label="是否生产" prop="isProduction" width="150">
            <template #default="scope">
              <el-tag :type="scope.row.isProduction ? 'success' : 'info'">
                {{ scope.row.isProduction ? '是' : '否' }}
                {{ scope.row.isProduction ? "是" : "否" }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column fixed="right"
                           label="操作"
                           min-width="60"
                           align="center"
                           v-if="operationType !== 'view'">
          <el-table-column
            fixed="right"
            label="操作"
            min-width="60"
            align="center"
            v-if="operationType !== 'view'"
          >
            <template #default="scope">
              <el-button link
                         type="primary"
                         size="small"
                         :disabled="isProductShipped(scope.row)"
                         @click="openProductForm('edit', scope.row,scope.$index)">编辑
              <el-button
                link
                type="primary"
                size="small"
                :disabled="isProductShipped(scope.row)"
                @click="openProductForm('edit', scope.row, scope.$index)"
                >编辑
              </el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-row :gutter="30">
          <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 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-row v-if="operationType !== 'view'" :gutter="30">
          <el-col :span="24">
            <el-form-item label="附件材料:"
                          prop="salesLedgerFiles">
              <FileUpload v-model:file-list="fileList"/>
            <el-form-item label="附件材料:" prop="salesLedgerFiles">
              <FileUpload
                v-model:file-list="fileList"
                :disabled="operationType === 'view'"
              />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </FormDialog>
    <!-- 从报价单导入(仅审批通过) -->
    <el-dialog v-model="quotationDialogVisible"
               title="选择审批通过的销售报价单"
               width="80%"
               :close-on-click-modal="false">
      <div style="margin-bottom: 12px; display:flex; gap: 12px; align-items:center;">
        <el-input v-model="quotationSearchForm.quotationNo"
                  placeholder="请输入报价单号"
                  clearable
                  style="max-width: 260px;"
                  @change="fetchQuotationList"/>
        <el-input v-model="quotationSearchForm.customer"
                  placeholder="请输入客户名称"
                  clearable
                  style="max-width: 260px;"
                  @change="fetchQuotationList"/>
        <el-button type="primary"
                   @click="fetchQuotationList">搜索
        </el-button>
    <el-dialog
      v-model="quotationDialogVisible"
      title="选择审批通过的销售报价单"
      width="80%"
      :close-on-click-modal="false"
    >
      <div
        style="
          margin-bottom: 12px;
          display: flex;
          gap: 12px;
          align-items: center;
        "
      >
        <el-input
          v-model="quotationSearchForm.quotationNo"
          placeholder="请输入报价单号"
          clearable
          style="max-width: 260px"
          @change="fetchQuotationList"
        />
        <el-input
          v-model="quotationSearchForm.customer"
          placeholder="请输入客户名称"
          clearable
          style="max-width: 260px"
          @change="fetchQuotationList"
        />
        <el-button type="primary" @click="fetchQuotationList">搜索 </el-button>
        <el-button @click="resetQuotationSearch">重置</el-button>
      </div>
      <el-table :data="quotationList"
                border
                stripe
                v-loading="quotationLoading"
                height="420px">
        <el-table-column align="center"
                         label="序号"
                         type="index"
                         width="60"/>
        <el-table-column prop="quotationNo"
                         label="报价单号"
                         width="180"
                         show-overflow-tooltip/>
        <el-table-column prop="customer"
                         label="客户名称"
                         min-width="220"
                         show-overflow-tooltip/>
        <el-table-column prop="salesperson"
                         label="业务员"
                         width="120"
                         show-overflow-tooltip/>
        <el-table-column prop="quotationDate"
                         label="报价日期"
                         width="140"/>
        <el-table-column prop="status"
                         label="审批状态"
                         width="120"
                         align="center"/>
        <el-table-column prop="totalAmount"
                         label="报价金额(元)"
                         width="160"
                         align="right">
      <el-table
        :data="quotationList"
        border
        stripe
        v-loading="quotationLoading"
        height="420px"
      >
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column
          prop="quotationNo"
          label="报价单号"
          width="180"
          show-overflow-tooltip
        />
        <el-table-column
          prop="customer"
          label="客户名称"
          min-width="220"
          show-overflow-tooltip
        />
        <el-table-column
          prop="salesperson"
          label="业务员"
          width="120"
          show-overflow-tooltip
        />
        <el-table-column prop="quotationDate" label="报价日期" width="140" />
        <el-table-column
          prop="status"
          label="审批状态"
          width="120"
          align="center"
        />
        <el-table-column
          prop="totalAmount"
          label="报价金额(元)"
          width="160"
          align="right"
        >
          <template #default="scope">
            {{ Number(scope.row.totalAmount ?? 0).toFixed(2) }}
          </template>
        </el-table-column>
        <el-table-column fixed="right"
                         label="操作"
                         width="120"
                         align="center">
        <el-table-column fixed="right" label="操作" width="120" align="center">
          <template #default="scope">
            <el-button type="primary"
                       link
                       @click="applyQuotation(scope.row)">选择
            <el-button type="primary" link @click="applyQuotation(scope.row)"
              >选择
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="quotationPage.total > 0"
                  :total="quotationPage.total"
                  layout="total, sizes, prev, pager, next, jumper"
                  :page="quotationPage.current"
                  :limit="quotationPage.size"
                  @pagination="quotationPaginationChange"/>
      <pagination
        v-show="quotationPage.total > 0"
        :total="quotationPage.total"
        layout="total, sizes, prev, pager, next, jumper"
        :page="quotationPage.current"
        :limit="quotationPage.size"
        @pagination="quotationPaginationChange"
      />
      <template #footer>
        <el-button @click="quotationDialogVisible = false">关闭</el-button>
      </template>
    </el-dialog>
    <FormDialog v-model="productFormVisible"
                :title="productOperationType === 'add' ? '新增产品' : '编辑产品'"
                :width="'40%'"
                :operation-type="productOperationType"
                @close="closeProductDia"
                @confirm="submitProduct"
                @cancel="closeProductDia">
      <el-form :model="productForm"
               label-width="140px"
               label-position="top"
               :rules="productRules"
               ref="productFormRef">
    <FormDialog
      v-model="productFormVisible"
      :title="productOperationType === 'add' ? '新增产品' : '编辑产品'"
      :width="'40%'"
      :operation-type="productOperationType"
      @close="closeProductDia"
      @confirm="submitProduct"
      @cancel="closeProductDia"
    >
      <el-form
        :model="productForm"
        label-width="140px"
        label-position="top"
        :rules="productRules"
        ref="productFormRef"
      >
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="产品大类:"
                          prop="productCategory">
              <el-tree-select v-model="productForm.productCategory"
                              placeholder="请选择"
                              clearable
                              filterable
                              check-strictly
                              @change="getModels"
                              :data="productOptions"
                              :render-after-expand="false"
                              style="width: 100%"/>
            <el-form-item label="产品大类:" prop="productCategory">
              <el-tree-select
                v-model="productForm.productCategory"
                placeholder="请选择"
                clearable
                filterable
                check-strictly
                @change="getModels"
                :data="productOptions"
                :render-after-expand="false"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="规格型号:"
                          prop="productModelId">
              <el-select v-model="productForm.productModelId"
                         placeholder="请选择"
                         clearable
                         @change="getProductModel"
                         filterable>
                <el-option v-for="item in modelOptions"
                           :key="item.id"
                           :label="item.model"
                           :value="item.id"/>
            <el-form-item label="规格型号:" prop="productModelId">
              <el-select
                v-model="productForm.productModelId"
                placeholder="请选择"
                clearable
                @change="getProductModel"
                filterable
              >
                <el-option
                  v-for="item in modelOptions"
                  :key="item.id"
                  :label="item.model"
                  :value="item.id"
                />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="单位:"
                          prop="unit">
              <el-input v-model="productForm.unit"
                        placeholder="请输入"
                        clearable/>
            <el-form-item label="单位:" prop="unit">
              <el-input
                v-model="productForm.unit"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="税率(%):"
                          prop="taxRate">
              <el-select v-model="productForm.taxRate"
                         placeholder="请选择"
                         clearable
                         @change="calculateFromTaxRate">
                <el-option label="1"
                           value="1"/>
                <el-option label="6"
                           value="6"/>
                <el-option label="13"
                           value="13"/>
            <el-form-item label="税率(%):" prop="taxRate">
              <el-select
                v-model="productForm.taxRate"
                placeholder="请选择"
                clearable
                @change="calculateFromTaxRate"
              >
                <el-option
                  v-for="dict in tax_rate"
                  :key="dict.value"
                  :label="dict.label"
                  :value="dict.value"
                />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税单价(元):"
                          prop="taxInclusiveUnitPrice">
              <el-input-number :step="0.01"
                               :min="0"
                               v-model="productForm.taxInclusiveUnitPrice"
                               style="width: 100%"
                               :precision="2"
                               placeholder="请输入"
                               clearable
                               @change="calculateFromUnitPrice"/>
            <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice">
              <el-input-number
                :step="0.01"
                :min="0"
                v-model="productForm.taxInclusiveUnitPrice"
                style="width: 100%"
                :precision="2"
                placeholder="请输入"
                clearable
                @change="calculateFromUnitPrice"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数量:"
                          prop="quantity">
              <el-input-number :step="0.1"
                               :min="0"
                               v-model="productForm.quantity"
                               placeholder="请输入"
                               clearable
                               :precision="2"
                               @change="calculateFromQuantity"
                               style="width: 100%"/>
            <el-form-item label="数量:" prop="quantity">
              <el-input-number
                :step="0.1"
                :min="0"
                v-model="productForm.quantity"
                placeholder="请输入"
                clearable
                :precision="2"
                @change="calculateFromQuantity"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税总价(元):"
                          prop="taxInclusiveTotalPrice">
              <el-input v-model="productForm.taxInclusiveTotalPrice"
                        placeholder="请输入"
                        clearable
                        @change="calculateFromTotalPrice"/>
            <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice">
              <el-input
                v-model="productForm.taxInclusiveTotalPrice"
                placeholder="请输入"
                clearable
                @change="calculateFromTotalPrice"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="不含税总价(元):"
                          prop="taxExclusiveTotalPrice">
              <el-input v-model="productForm.taxExclusiveTotalPrice"
                        placeholder="请输入"
                        clearable
                        @change="calculateFromExclusiveTotalPrice"/>
            <el-form-item
              label="不含税总价(元):"
              prop="taxExclusiveTotalPrice"
            >
              <el-input
                v-model="productForm.taxExclusiveTotalPrice"
                placeholder="请输入"
                clearable
                @change="calculateFromExclusiveTotalPrice"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="发票类型:"
                          prop="invoiceType">
              <el-select v-model="productForm.invoiceType"
                         placeholder="请选择"
                         clearable>
                <el-option label="增普票"
                           value="增普票"/>
                <el-option label="增专票"
                           value="增专票"/>
            <el-form-item label="发票类型:" prop="invoiceType">
              <el-select
                v-model="productForm.invoiceType"
                placeholder="请选择"
                clearable
              >
                <el-option label="增普票" value="增普票" />
                <el-option label="增专票" value="增专票" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="是否生产:"
                          prop="isProduction">
            <el-form-item label="是否生产:" prop="isProduction">
              <el-radio-group v-model="productForm.isProduction">
                <el-radio label="是"
                          :value="true"/>
                <el-radio label="否"
                          :value="false"/>
                <el-radio label="是" :value="true" />
                <el-radio label="否" :value="false" />
              </el-radio-group>
            </el-form-item>
          </el-col>
@@ -727,34 +848,35 @@
      </el-form>
    </FormDialog>
    <!-- 导入弹窗 -->
    <FormDialog v-model="importUpload.open"
                :title="importUpload.title"
                :width="'600px'"
                @close="importUpload.open = false"
                @confirm="submitImportFile"
                @cancel="importUpload.open = false">
      <el-upload ref="importUploadRef"
                 :limit="1"
                 accept=".xlsx,.xls"
                 :action="importUpload.url"
                 :headers="importUpload.headers"
                 :before-upload="importUpload.beforeUpload"
                 :on-success="importUpload.onSuccess"
                 :on-error="importUpload.onError"
                 :on-progress="importUpload.onProgress"
                 :on-change="importUpload.onChange"
                 :auto-upload="false"
                 drag>
    <FormDialog
      v-model="importUpload.open"
      :title="importUpload.title"
      :width="'600px'"
      @close="importUpload.open = false"
      @confirm="submitImportFile"
      @cancel="importUpload.open = false"
    >
      <el-upload
        ref="importUploadRef"
        :limit="1"
        accept=".xlsx,.xls"
        :action="importUpload.url"
        :headers="importUpload.headers"
        :before-upload="importUpload.beforeUpload"
        :on-success="importUpload.onSuccess"
        :on-error="importUpload.onError"
        :on-progress="importUpload.onProgress"
        :on-change="importUpload.onChange"
        :auto-upload="false"
        drag
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">
          将文件拖到此处,或<em>点击上传</em>
        </div>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <template #tip>
          <div class="el-upload__tip">
            仅支持 xls/xlsx,大小不超过 10MB。
            <el-button link
                       type="primary"
                       @click="downloadTemplate">下载导入模板
            <el-button link type="primary" @click="downloadTemplate"
              >下载导入模板
            </el-button>
          </div>
        </template>
@@ -762,33 +884,50 @@
    </FormDialog>
    <!-- // todo 附件预览相关 -->
    <!-- 附件列表弹窗 -->
    <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="sales_ledger"
              :record-id="recordId"/>
    <FileList
      v-if="fileDialogVisible"
      v-model:visible="fileDialogVisible"
      record-type="sales_ledger"
      :record-id="recordId"
    />
    <!-- 打印预览弹窗 -->
    <el-dialog v-model="printPreviewVisible"
               title="打印预览"
               width="90%"
               :close-on-click-modal="false"
               class="print-preview-dialog">
    <el-dialog
      v-model="printPreviewVisible"
      title="打印预览"
      width="90%"
      :close-on-click-modal="false"
      class="print-preview-dialog"
    >
      <div class="print-preview-container">
        <div class="print-preview-header">
          <el-button type="primary"
                     @click="executePrint">执行打印
          </el-button>
          <el-button type="primary" @click="executePrint">执行打印 </el-button>
          <el-button @click="printPreviewVisible = false">关闭预览</el-button>
        </div>
        <div class="print-preview-content">
          <div v-if="printData.length === 0"
               style="text-align: center; padding: 50px; color: #999;">
          <div
            v-if="printData.length === 0"
            style="text-align: center; padding: 50px; color: #999"
          >
            暂无打印数据
          </div>
          <div v-else
               style="text-align: center; padding: 10px; color: #666; font-size: 14px; background: #e8f4fd; margin-bottom: 10px;">
          <div
            v-else
            style="
              text-align: center;
              padding: 10px;
              color: #666;
              font-size: 14px;
              background: #e8f4fd;
              margin-bottom: 10px;
            "
          >
            共 {{ printData.length }} 条数据待打印
          </div>
          <div v-for="(item, index) in printData"
               :key="index"
               class="print-page">
          <div
            v-for="(item, index) in printData"
            :key="index"
            class="print-page"
          >
            <div class="delivery-note">
              <div class="header">
                <div class="document-title">零售发货单</div>
@@ -816,40 +955,43 @@
              <div class="table-section">
                <table class="product-table">
                  <thead>
                  <tr>
                    <th>产品名称</th>
                    <th>规格型号</th>
                    <th>单位</th>
                    <th>单价</th>
                    <th>零售数量</th>
                    <th>零售金额</th>
                  </tr>
                    <tr>
                      <th>产品名称</th>
                      <th>规格型号</th>
                      <th>单位</th>
                      <th>单价</th>
                      <th>零售数量</th>
                      <th>零售金额</th>
                    </tr>
                  </thead>
                  <tbody>
                  <tr v-for="product in item.products"
                      :key="product.id">
                    <td>{{ product.productCategory || '' }}</td>
                    <td>{{ product.specificationModel || '' }}</td>
                    <td>{{ product.unit || '' }}</td>
                    <td>{{ product.taxInclusiveUnitPrice || '0' }}</td>
                    <td>{{ product.quantity || '0' }}</td>
                    <td>{{ product.taxInclusiveTotalPrice || '0' }}</td>
                  </tr>
                  <tr v-if="!item.products || item.products.length === 0">
                    <td colspan="6"
                        style="text-align: center; color: #999;">暂无产品数据
                    </td>
                  </tr>
                    <tr v-for="product in item.products" :key="product.id">
                      <td>{{ product.productCategory || "" }}</td>
                      <td>{{ product.specificationModel || "" }}</td>
                      <td>{{ product.unit || "" }}</td>
                      <td>{{ product.taxInclusiveUnitPrice || "0" }}</td>
                      <td>{{ product.quantity || "0" }}</td>
                      <td>{{ product.taxInclusiveTotalPrice || "0" }}</td>
                    </tr>
                    <tr v-if="!item.products || item.products.length === 0">
                      <td colspan="6" style="text-align: center; color: #999">
                        暂无产品数据
                      </td>
                    </tr>
                  </tbody>
                  <tfoot>
                  <tr>
                    <td class="label">合计</td>
                    <td class="total-value"></td>
                    <td class="total-value"></td>
                    <td class="total-value"></td>
                    <td class="total-value">{{ getTotalQuantity(item.products) }}</td>
                    <td class="total-value">{{ getTotalAmount(item.products) }}</td>
                  </tr>
                    <tr>
                      <td class="label">合计</td>
                      <td class="total-value"></td>
                      <td class="total-value"></td>
                      <td class="total-value"></td>
                      <td class="total-value">
                        {{ getTotalQuantity(item.products) }}
                      </td>
                      <td class="total-value">
                        {{ getTotalAmount(item.products) }}
                      </td>
                    </tr>
                  </tfoot>
                </table>
              </div>
@@ -871,7 +1013,9 @@
                <div class="footer-row">
                  <div class="footer-item">
                    <span class="label">操作员:</span>
                    <span class="value">{{ userStore.nickName || '撕开前' }}</span>
                    <span class="value">{{
                      userStore.nickName || "撕开前"
                    }}</span>
                  </div>
                  <div class="footer-item">
                    <span class="label">打印日期:</span>
@@ -885,61 +1029,127 @@
      </div>
    </el-dialog>
    <!-- 发货弹框 -->
    <el-dialog v-model="deliveryFormVisible"
               title="发货信息"
               width="40%"
               @close="closeDeliveryDia">
      <el-form :model="deliveryForm"
               label-width="120px"
               label-position="top"
               :rules="deliveryRules"
               ref="deliveryFormRef">
    <el-dialog
      v-model="deliveryFormVisible"
      title="发货信息"
      width="40%"
      @close="closeDeliveryDia"
    >
      <el-form
        :model="deliveryForm"
        label-width="120px"
        label-position="top"
        :rules="deliveryRules"
        ref="deliveryFormRef"
      >
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="发货类型:"
                          prop="type">
              <el-select v-model="deliveryForm.type"
                         placeholder="请选择发货类型"
                         style="width: 100%">
                <el-option label="货车"
                           value="货车"/>
                <el-option label="快递"
                           value="快递"/>
            <el-form-item label="发货类型:" prop="type">
              <el-select
                v-model="deliveryForm.type"
                placeholder="请选择发货类型"
                style="width: 100%"
                @change="handleDeliveryTypeChange"
              >
                <el-option label="货车" value="货车" />
                <el-option label="快递" value="快递" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="待发货数量:">
              <el-input
                :model-value="currentDeliveryRow?.noQuantity"
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24" v-if="deliveryForm.type === '货车'">
            <el-form-item label="发货车牌号:" prop="shippingCarNumber">
              <el-input
                v-model="deliveryForm.shippingCarNumber"
                placeholder="请输入发货车牌号"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="24" v-else>
            <el-form-item label="快递公司:" prop="expressCompany">
              <el-input
                v-model="deliveryForm.expressCompany"
                placeholder="请输入快递公司"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30" v-if="deliveryForm.type === '快递'">
          <el-col :span="24">
            <el-form-item label="快递单号:" prop="expressNumber">
              <el-input
                v-model="deliveryForm.expressNumber"
                placeholder="请输入快递单号"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="批号:"
                          prop="batchNo">
              <el-table :data="deliveryForm.batchNoList"
                        border
                        size="small"
                        max-height="260"
                        style="width: 100%;">
                <el-table-column label="批号"
                                 prop="batchNo"
                                 min-width="180"/>
                <el-table-column label="数量"
                                 min-width="120"
                                 align="center">
            <el-form-item label="发货图片:">
              <ImageUpload v-model:file-list="deliveryFileList" :limit="9" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="库存:" prop="batchNo">
              <el-table
                :data="deliveryForm.batchNoList"
                border
                size="small"
                max-height="260"
                style="width: 100%"
              >
                <el-table-column label="批号" prop="batchNo" min-width="180" />
                <el-table-column
                  label="产品大类"
                  prop="productName"
                  min-width="100"
                />
                <el-table-column
                  label="规格型号"
                  prop="model"
                  min-width="100"
                />
                <el-table-column label="单位" prop="unit" min-width="100" />
                <el-table-column
                  label="库存数量"
                  min-width="120"
                  align="center"
                >
                  <template #default="scope">
                    {{ getDeliveryBatchQuantity(scope.row) }}
                  </template>
                </el-table-column>
                <el-table-column label="发货数量"
                                 min-width="160"
                                 align="center">
                <el-table-column
                  label="发货数量"
                  min-width="160"
                  align="center"
                >
                  <template #default="scope">
                    <el-input-number v-model="scope.row.deliveryQuantity"
                                     :min="0"
                                     :max="getDeliveryBatchDeliveryMax(scope.row)"
                                     :precision="2"
                                     :step="0.01"
                                     controls-position="right"
                                     @change="handleDeliveryBatchQuantityChange(scope.row)"
                                     style="width: 100%;"/>
                    <el-input-number
                      v-model="scope.row.deliveryQuantity"
                      :min="0"
                      :max="getDeliveryBatchDeliveryMax(scope.row)"
                      :precision="2"
                      :step="0.01"
                      controls-position="right"
                      @change="handleDeliveryBatchQuantityChange(scope.row)"
                      style="width: 100%"
                    />
                  </template>
                </el-table-column>
              </el-table>
@@ -949,8 +1159,8 @@
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary"
                     @click="submitDelivery">确认发货
          <el-button type="primary" @click="submitDelivery"
            >确认发货
          </el-button>
          <el-button @click="closeDeliveryDia">取消</el-button>
        </div>
@@ -960,15 +1170,15 @@
</template>
<script setup>
import {getToken} from "@/utils/auth";
import { getToken } from "@/utils/auth";
import pagination from "@/components/PIMTable/Pagination.vue";
import {onMounted, ref, getCurrentInstance} from "vue";
import {addShippingInfo} from "@/api/salesManagement/deliveryLedger.js";
import {ElMessageBox, ElMessage} from "element-plus";
import { onMounted, ref, getCurrentInstance } from "vue";
import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
import { ElMessageBox, ElMessage } from "element-plus";
import useUserStore from "@/store/modules/user";
import {userListNoPage} from "@/api/system/user.js";
import { userListNoPage } from "@/api/system/user.js";
import FormDialog from "@/components/Dialog/FormDialog.vue";
import {getQuotationList} from "@/api/salesManagement/salesQuotation.js";
import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
import {
  ledgerListPage,
  productList,
@@ -981,21 +1191,24 @@
  delLedgerFile,
  getProductInventory,
} from "@/api/salesManagement/salesLedger.js";
import {getStockInventoryByModelId} from "@/api/inventoryManagement/stockInventory.js";
import {modelList, productTreeList} from "@/api/basicData/product.js";
import { getStockInventoryByModelId } from "@/api/inventoryManagement/stockInventory.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 {useRouter, useRoute} from "vue-router";
import {listCustomerPrivatePool} from "@/api/basicData/customerFile.js";
import FileUpload from "@/components/AttachmentUpload/file/index.vue";
import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
import { getCurrentDate } from "@/utils/index.js";
import { listCustomer } from "@/api/basicData/customer.js";
const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
const FileList = defineAsyncComponent(() =>
  import("@/components/Dialog/FileList.vue")
);
const router = useRouter();
const route = useRoute();
const userStore = useUserStore();
const {proxy} = getCurrentInstance();
const { proxy } = getCurrentInstance();
const { tax_rate } = proxy.useDict("tax_rate");
const tableData = ref([]);
const productData = ref([]);
const selectedRows = ref([]);
@@ -1011,6 +1224,7 @@
});
const total = ref(0);
const fileList = ref([]);
const deliveryFileList = ref([]);
// 用户信息表单弹框数据
const operationType = ref("");
@@ -1025,6 +1239,7 @@
  },
  form: {
    salesContractNo: "",
    autoGenerateContractNo: true,
    salesman: "",
    customerId: "",
    entryPerson: "",
@@ -1034,18 +1249,19 @@
    productData: [],
    executionDate: "",
    hasProductionRecord: false,
    createTime: "",
  },
  rules: {
    salesman: [{required: true, message: "请选择", trigger: "change"}],
    customerId: [{required: true, message: "请选择", trigger: "change"}],
    entryPerson: [{required: true, message: "请选择", trigger: "change"}],
    entryDate: [{required: true, message: "请选择", trigger: "change"}],
    deliveryDate: [{required: true, message: "请选择", trigger: "change"}],
    executionDate: [{required: true, message: "请选择", trigger: "change"}],
    salesman: [{ required: true, message: "请选择", trigger: "change" }],
    customerId: [{ required: true, message: "请选择", trigger: "change" }],
    entryPerson: [{ required: true, message: "请选择", trigger: "change" }],
    entryDate: [{ required: true, message: "请选择", trigger: "change" }],
    deliveryDate: [{ required: true, message: "请选择", trigger: "change" }],
    executionDate: [{ required: true, message: "请选择", trigger: "change" }],
  },
});
const {form, rules} = toRefs(data);
const {form: searchForm} = useFormData(data.searchForm);
const { form, rules } = toRefs(data);
const { form: searchForm } = useFormData(data.searchForm);
// 产品表单弹框数据
const productFormVisible = ref(false);
const productOperationType = ref("");
@@ -1064,28 +1280,28 @@
    isProduction: false,
  },
  productRules: {
    productCategory: [{required: true, message: "请选择", trigger: "change"}],
    productModelId: [{required: true, message: "请选择", trigger: "change"}],
    productCategory: [{ required: true, message: "请选择", trigger: "change" }],
    productModelId: [{ required: true, message: "请选择", trigger: "change" }],
    specificationModel: [
      {required: true, message: "请选择", trigger: "change"},
      { required: true, message: "请选择", trigger: "change" },
    ],
    unit: [{required: true, message: "请输入", trigger: "blur"}],
    quantity: [{required: true, message: "请输入", trigger: "blur"}],
    unit: [{ required: true, message: "请输入", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入", trigger: "blur" }],
    taxInclusiveUnitPrice: [
      {required: true, message: "请输入", trigger: "blur"},
      { required: true, message: "请输入", trigger: "blur" },
    ],
    taxRate: [{required: true, message: "请选择", trigger: "change"}],
    taxRate: [{ required: true, message: "请选择", trigger: "change" }],
    taxInclusiveTotalPrice: [
      {required: true, message: "请输入", trigger: "blur"},
      { required: true, message: "请输入", trigger: "blur" },
    ],
    taxExclusiveTotalPrice: [
      {required: true, message: "请输入", trigger: "blur"},
      { required: true, message: "请输入", trigger: "blur" },
    ],
    invoiceType: [{required: true, message: "请选择", trigger: "change"}],
    isProduction: [{required: true, message: "请选择", trigger: "change"}],
    invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
    isProduction: [{ required: true, message: "请选择", trigger: "change" }],
  },
});
const {productForm, productRules} = toRefs(productFormData);
const { productForm, productRules } = toRefs(productFormData);
// 防止循环计算的标志
const isCalculating = ref(false);
// 打印相关
@@ -1111,74 +1327,114 @@
// 发货相关
const deliveryFormVisible = ref(false);
const currentDeliveryRow = ref(null);
const getDeliveryBatchQuantity = item => {
  const quantity = item?.qualitity
      ?? item?.quantity
      ?? item?.unLockedQuantity
      ?? item?.qualifiedUnLockedQuantity
      ?? item?.qualifiedQuantity
      ?? item?.stockQuantity;
const getDeliveryBatchQuantity = (item) => {
  const quantity =
    item?.qualitity ??
    item?.quantity ??
    item?.unLockedQuantity ??
    item?.qualifiedUnLockedQuantity ??
    item?.qualifiedQuantity ??
    item?.stockQuantity;
  return quantity ?? 0;
};
const getCurrentDeliveryRowQuantity = () => {
  return Number(currentDeliveryRow.value?.noQuantity || 0);
};
const getDeliveryBatchDeliveryMax = row => {
const getDeliveryBatchDeliveryMax = (row) => {
  const productQuantity = getCurrentDeliveryRowQuantity();
  const batchQuantity = Number(getDeliveryBatchQuantity(row) || 0);
  const otherBatchTotal = (deliveryForm.value.batchNoList || []).reduce(
      (sum, item) => {
        if (item?.id === row?.id) return sum;
        return sum + Number(item?.deliveryQuantity || 0);
      },
      0
    (sum, item) => {
      if (item?.id === row?.id) return sum;
      return sum + Number(item?.deliveryQuantity || 0);
    },
    0
  );
  const remainingProductQuantity = Math.max(
      0,
      productQuantity - otherBatchTotal
    0,
    productQuantity - otherBatchTotal
  );
  return Math.max(0, Math.min(batchQuantity, remainingProductQuantity));
};
const handleDeliveryBatchQuantityChange = row => {
  const max = getDeliveryBatchDeliveryMax(row);
const handleDeliveryBatchQuantityChange = (row) => {
  const productQuantity = getCurrentDeliveryRowQuantity();
  const batchQuantity = Number(getDeliveryBatchQuantity(row) || 0);
  const otherBatchTotal = (deliveryForm.value.batchNoList || []).reduce(
    (sum, item) => {
      if (item?.id === row?.id) return sum;
      return sum + Number(item?.deliveryQuantity || 0);
    },
    0
  );
  const remainingProductQuantity = Math.max(
    0,
    productQuantity - otherBatchTotal
  );
  const currentValue = Number(row?.deliveryQuantity || 0);
  if (currentValue > max) {
    row.deliveryQuantity = max;
    proxy.$modal.msgWarning("发货数量不能超过这个产品的数量");
  if (currentValue > batchQuantity) {
    row.deliveryQuantity = batchQuantity;
    proxy.$modal.msgWarning("发货数量不能大于库存数量");
  } else if (currentValue > remainingProductQuantity) {
    row.deliveryQuantity = remainingProductQuantity;
    proxy.$modal.msgWarning("所有批次发货数量之和不能大于待发货数量");
  }
};
const getSelectedDeliveryBatchRows = () => {
  return (deliveryForm.value.batchNoList || []).filter(
      item => Number(item?.deliveryQuantity || 0) > 0
    (item) => Number(item?.deliveryQuantity || 0) > 0
  );
};
const getDeliveryBatchNoList = async productModelId => {
const getDeliveryBatchNoList = async (productModelId) => {
  if (!productModelId) return [];
  const res = await getStockInventoryByModelId(productModelId);
  const rawList = Array.isArray(res?.data)
      ? res.data
      : res?.data?.records || res?.data?.rows || [];
    ? res.data
    : res?.data?.records || res?.data?.rows || [];
  const seenIds = new Set();
  return rawList.filter(item => {
    if (!item?.id || !item?.batchNo || seenIds.has(item.id)) {
      return false;
    }
    seenIds.add(item.id);
    return true;
  }).map(item => ({
    ...item,
    deliveryQuantity: 0,
  }));
  return rawList
    .filter((item) => {
      if (!item?.id || !item?.batchNo || seenIds.has(item.id)) {
        return false;
      }
      seenIds.add(item.id);
      return true;
    })
    .map((item) => ({
      ...item,
      deliveryQuantity: 0,
    }));
};
const validateDeliveryShippingCarNumber = (_rule, value, callback) => {
  if (deliveryForm.value.type === "货车" && !value) {
    return callback(new Error("请输入发货车牌号"));
  }
  callback();
};
const validateDeliveryExpressCompany = (_rule, value, callback) => {
  if (deliveryForm.value.type === "快递" && !value) {
    return callback(new Error("请输入快递公司"));
  }
  callback();
};
const deliveryFormData = reactive({
  deliveryForm: {
    shippingCarNumber: "",
    expressCompany: "",
    expressNumber: "",
    type: "货车", // 货车, 快递
  },
  deliveryRules: {
    type: [{required: true, message: "请选择发货类型", trigger: "change"}],
    shippingCarNumber: [
      { validator: validateDeliveryShippingCarNumber, trigger: "blur" },
    ],
    expressCompany: [
      { validator: validateDeliveryExpressCompany, trigger: "blur" },
    ],
    type: [{ required: true, message: "请选择发货类型", trigger: "change" }],
  },
});
const {deliveryForm, deliveryRules} = toRefs(deliveryFormData);
const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
// 导入相关
const importUploadRef = ref(null);
@@ -1186,9 +1442,9 @@
  title: "导入销售台账",
  open: false,
  url: import.meta.env.VITE_APP_BASE_API + "/sales/ledger/import",
  headers: {Authorization: "Bearer " + getToken()},
  headers: { Authorization: "Bearer " + getToken() },
  isUploading: false,
  beforeUpload: file => {
  beforeUpload: (file) => {
    const isExcel = file.name.endsWith(".xlsx") || file.name.endsWith(".xls");
    const isLt10M = file.size / 1024 / 1024 < 10;
    if (!isExcel) {
@@ -1228,7 +1484,7 @@
  },
});
const changeDaterange = value => {
const changeDaterange = (value) => {
  if (value) {
    searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
    searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
@@ -1250,36 +1506,36 @@
  expandedRowKeys.value = [];
  getList();
};
const paginationChange = obj => {
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList();
};
const getList = () => {
  tableLoading.value = true;
  const {entryDate, ...rest} = searchForm;
  const { entryDate, ...rest } = searchForm;
  // 将范围日期字段传递给后端
  const params = {...rest, ...page};
  const params = { ...rest, ...page };
  // 移除录入日期的默认值设置,只保留范围日期字段
  delete params.entryDate;
  return ledgerListPage(params)
      .then(res => {
        tableLoading.value = false;
        tableData.value = res.records;
        tableData.value.map(item => {
          item.children = [];
        });
        total.value = res.total;
        return res;
      })
      .catch(() => {
        tableLoading.value = false;
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.records;
      tableData.value.map((item) => {
        item.children = [];
      });
      total.value = res.total;
      return res;
    })
    .catch(() => {
      tableLoading.value = false;
    });
};
// 获取产品大类tree数据
const getProductOptions = () => {
  // 返回 Promise,便于在编辑产品时等待加载完成
  return productTreeList().then(res => {
  return productTreeList().then((res) => {
    productOptions.value = convertIdToValue(res);
    return productOptions.value;
  });
@@ -1290,53 +1546,53 @@
  }
  return parseFloat(cellValue).toFixed(2);
};
const findLedgerRecordByRow = row => {
const findLedgerRecordByRow = (row) => {
  if (!row) return null;
  if (
      row.maintainer !== undefined ||
      row.maintainerName !== undefined ||
      row.entryPerson !== undefined ||
      row.entryPersonName !== undefined
    row.maintainer !== undefined ||
    row.maintainerName !== undefined ||
    row.entryPerson !== undefined ||
    row.entryPersonName !== undefined
  ) {
    return row;
  }
  if (row.salesLedgerId !== undefined && row.salesLedgerId !== null) {
    return (
        tableData.value.find(
            item => String(item.id) === String(row.salesLedgerId)
        ) || null
      tableData.value.find(
        (item) => String(item.id) === String(row.salesLedgerId)
      ) || null
    );
  }
  return null;
};
const isCurrentUserMaintainer = row => {
const isCurrentUserMaintainer = (row) => {
  const ledgerRecord = findLedgerRecordByRow(row);
  if (!ledgerRecord) return true;
  const currentUserId = String(userStore.id ?? "");
  const currentNickName = String(userStore.nickName ?? "").trim();
  const maintainerId = ledgerRecord.maintainerId ?? ledgerRecord.entryPerson;
  const maintainerName =
      ledgerRecord.maintainerName ??
      ledgerRecord.maintainer ??
      ledgerRecord.entryPersonName;
    ledgerRecord.maintainerName ??
    ledgerRecord.maintainer ??
    ledgerRecord.entryPersonName;
  if (
      maintainerId !== undefined &&
      maintainerId !== null &&
      String(maintainerId) !== ""
    maintainerId !== undefined &&
    maintainerId !== null &&
    String(maintainerId) !== ""
  ) {
    return String(maintainerId) === currentUserId;
  }
  if (
      maintainerName !== undefined &&
      maintainerName !== null &&
      String(maintainerName).trim() !== ""
    maintainerName !== undefined &&
    maintainerName !== null &&
    String(maintainerName).trim() !== ""
  ) {
    return String(maintainerName).trim() === currentNickName;
  }
  return true;
};
const canEditLedger = row => isCurrentUserMaintainer(row);
const canDeleteLedger = row => isCurrentUserMaintainer(row);
const canEditLedger = (row) => isCurrentUserMaintainer(row);
const canDeleteLedger = (row) => isCurrentUserMaintainer(row);
const sensitiveAmountFormatter = (row, column, cellValue) => {
  if (!isCurrentUserMaintainer(row)) {
    return "*****";
@@ -1344,14 +1600,14 @@
  return formattedNumber(row, column, cellValue);
};
// 获取tree子数据
const getModels = value => {
const getModels = (value) => {
  productForm.value.productCategory = findNodeById(productOptions.value, value);
  modelList({id: value}).then(res => {
  modelList({ id: value }).then((res) => {
    modelOptions.value = res;
  });
};
const getProductModel = value => {
  const index = modelOptions.value.findIndex(item => item.id === value);
const getProductModel = (value) => {
  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;
@@ -1376,8 +1632,8 @@
};
function convertIdToValue(data) {
  return data.map(item => {
    const {id, children, ...rest} = item;
  return data.map((item) => {
    const { id, children, ...rest } = item;
    const newItem = {
      ...rest,
      value: id, // 将 id 改为 value
@@ -1405,12 +1661,12 @@
}
// 表格选择数据
const handleSelectionChange = selection => {
const handleSelectionChange = (selection) => {
  // 过滤掉子数据
  selectedRows.value = selection.filter(item => item.children !== undefined);
  selectedRows.value = selection.filter((item) => item.children !== undefined);
  console.log("selection", selectedRows.value);
};
const productSelected = selectedRows => {
const productSelected = (selectedRows) => {
  productSelectedRows.value = selectedRows;
};
const expandedRowKeys = ref([]);
@@ -1419,8 +1675,8 @@
  if (expandedRows.length > 0) {
    expandedRowKeys.value = [];
    try {
      productList({salesLedgerId: row.id, type: 1}).then(res => {
        const index = tableData.value.findIndex(item => item.id === row.id);
      productList({ salesLedgerId: row.id, type: 1 }).then((res) => {
        const index = tableData.value.findIndex((item) => item.id === row.id);
        if (index > -1) {
          tableData.value[index].children = res.data;
        }
@@ -1435,7 +1691,7 @@
};
// 添加表行类名方法
const tableRowClassName = ({row}) => {
const tableRowClassName = ({ row }) => {
  if (!row.deliveryDate) return "";
  if (row.isFh) return "";
@@ -1451,7 +1707,7 @@
  }
};
// 主表合计方法
const summarizeMainTable = param => {
const summarizeMainTable = (param) => {
  return proxy.summarizeTable(param, [
    "contractAmount",
    "taxInclusiveTotalPrice",
@@ -1461,17 +1717,17 @@
// 子表合计方法
const summarizeChildrenTable = (param, parentRow) => {
  if (!isCurrentUserMaintainer(parentRow)) {
    const {columns} = param;
    const { columns } = param;
    return columns.map((column, index) => {
      if (index === 0) {
        return "合计";
      }
      if (
          [
            "taxInclusiveUnitPrice",
            "taxInclusiveTotalPrice",
            "taxExclusiveTotalPrice",
          ].includes(column.property)
        [
          "taxInclusiveUnitPrice",
          "taxInclusiveTotalPrice",
          "taxExclusiveTotalPrice",
        ].includes(column.property)
      ) {
        return "*****";
      }
@@ -1496,7 +1752,7 @@
  selectedQuotation.value = null;
  let userLists = await userListNoPage();
  userList.value = userLists.data;
  listCustomerPrivatePool({current: -1, size: -1}).then(res => {
  listCustomer({ current: -1, size: -1, type: 0 }).then((res) => {
    customerOption.value = res.data.records;
  });
  form.value.entryPerson = userStore.id;
@@ -1505,13 +1761,19 @@
    form.value.entryDate = getCurrentDate();
    // 签订日期默认为当天
    form.value.executionDate = getCurrentDate();
    // 创建时间默认为当天
    form.value.createTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
    // 默认自动生成销售合同号
    form.value.autoGenerateContractNo = true;
  } else {
    currentId.value = row.id;
    getSalesLedgerWithProducts({id: row.id, type: 1}).then(res => {
      form.value = {...res};
    getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
      form.value = { ...res };
      form.value.entryPerson = Number(res.entryPerson);
      productData.value = form.value.productData;
      fileList.value = form.value.storageBlobVOs;
      // 编辑时设置自动生成为false,允许手动修改
      form.value.autoGenerateContractNo = false;
    });
  }
  // let userAll = await userStore.getInfo()
@@ -1533,7 +1795,7 @@
  // 先确保客户列表已加载,便于后续回填 customerId
  if (!customerOption.value || customerOption.value.length === 0) {
    try {
      listCustomerPrivatePool({current: -1, size: -1}).then(res => {
      listCustomer({ current: -1, size: -1 }).then((res) => {
        customerOption.value = res.data.records;
      });
    } catch (e) {
@@ -1569,14 +1831,14 @@
};
// 报价单弹框分页切换
const quotationPaginationChange = obj => {
const quotationPaginationChange = (obj) => {
  quotationPage.current = obj.page;
  quotationPage.size = obj.limit;
  fetchQuotationList();
};
// 选中报价单后回填到台账表单
const applyQuotation = row => {
const applyQuotation = (row) => {
  if (!row) return;
  selectedQuotation.value = row;
@@ -1585,12 +1847,12 @@
  // 客户名称 -> customerId
  const qCustomerName = String(row.customer || "").trim();
  const customer = (customerOption.value || []).find(c => {
  const customer = (customerOption.value || []).find((c) => {
    const name = String(c.customerName || "").trim();
    return (
        name === qCustomerName ||
        name.includes(qCustomerName) ||
        qCustomerName.includes(name)
      name === qCustomerName ||
      name.includes(qCustomerName) ||
      qCustomerName.includes(name)
    );
  });
  if (customer?.id) {
@@ -1602,14 +1864,14 @@
  // 产品信息映射:报价 products -> 台账 productData
  const products = Array.isArray(row.products) ? row.products : [];
  productData.value = products.map(p => {
  productData.value = products.map((p) => {
    const quantity = Number(p.quantity ?? 0) || 0;
    const unitPrice = Number(p.unitPrice ?? 0) || 0;
    const taxRate = "13"; // 默认 13%,便于直接提交(如需可在产品中自行修改)
    const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
    const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(
        taxInclusiveTotalPrice,
        taxRate
      taxInclusiveTotalPrice,
      taxRate
    );
    return {
      // 台账字段
@@ -1623,6 +1885,8 @@
      taxExclusiveTotalPrice: taxExclusiveTotalPrice,
      invoiceType: "增普票",
      isProduction: true,
      productId: p.productId,
      productModelId: p.productModelId,
    };
  });
@@ -1635,7 +1899,7 @@
// 提交表单
const submitForm = () => {
  proxy.$refs["formRef"].validate(valid => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      console.log("productData.value--", productData.value);
      if (productData.value !== null && productData.value.length > 0) {
@@ -1646,7 +1910,10 @@
      }
      form.value.storageBlobDTOs = fileList;
      form.value.type = 1;
      addOrUpdateSalesLedger(form.value).then(res => {
      if (form.value.autoGenerateContractNo) {
        form.value.salesContractNo = "";
      }
      addOrUpdateSalesLedger(form.value).then((res) => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
        expandedRowKeys.value = [];
@@ -1677,24 +1944,24 @@
  }
  proxy.resetForm("productFormRef");
  if (type === "edit") {
    productForm.value = {...row};
    productForm.value = { ...row };
    productIndex.value = index;
    // 编辑时根据产品大类名称反查 tree 节点 id,并加载规格型号列表
    try {
      const options =
          productOptions.value && productOptions.value.length > 0
              ? productOptions.value
              : await getProductOptions();
        productOptions.value && productOptions.value.length > 0
          ? productOptions.value
          : await getProductOptions();
      const categoryId = findNodeIdByLabel(
          options,
          productForm.value.productCategory
        options,
        productForm.value.productCategory
      );
      if (categoryId) {
        const models = await modelList({id: categoryId});
        const models = await modelList({ id: categoryId });
        modelOptions.value = models || [];
        // 根据当前规格型号名称反查并设置 productModelId,便于下拉框显示已选值
        const currentModel = (modelOptions.value || []).find(
            m => m.model === productForm.value.specificationModel
          (m) => m.model === productForm.value.specificationModel
        );
        if (currentModel) {
          productForm.value.productModelId = currentModel.id;
@@ -1711,15 +1978,15 @@
};
// 提交产品表单
const submitProduct = () => {
  proxy.$refs["productFormRef"].validate(valid => {
  proxy.$refs["productFormRef"].validate((valid) => {
    if (valid) {
      if (operationType.value === "edit") {
        submitProductEdit();
      } else {
        if (productOperationType.value === "add") {
          productData.value.push({...productForm.value});
          productData.value.push({ ...productForm.value });
        } else {
          productData.value[productIndex.value] = {...productForm.value};
          productData.value[productIndex.value] = { ...productForm.value };
        }
        closeProductDia();
      }
@@ -1729,10 +1996,10 @@
const submitProductEdit = () => {
  productForm.value.salesLedgerId = currentId.value;
  productForm.value.type = 1;
  addOrUpdateSalesLedgerProduct(productForm.value).then(res => {
  addOrUpdateSalesLedgerProduct(productForm.value).then((res) => {
    proxy.$modal.msgSuccess("提交成功");
    closeProductDia();
    getSalesLedgerWithProducts({id: currentId.value, type: 1}).then(res => {
    getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then((res) => {
      productData.value = res.productData;
    });
  });
@@ -1745,47 +2012,49 @@
  }
  // 检查是否有已发货或审核通过的产品
  const shippedProducts = productSelectedRows.value.filter(row =>
      isProductShipped(row)
  const shippedProducts = productSelectedRows.value.filter((row) =>
    isProductShipped(row)
  );
  if (shippedProducts.length > 0) {
    proxy.$modal.msgWarning("已发货或审核通过的产品不能删除");
    return;
  }
  // 检查是否只剩一条数据,销售台账至少保留一条产品
  if (productData.value.length <= 1) {
    proxy.$modal.msgWarning("销售台账至少需要保留一条产品数据");
    return;
  }
  if (operationType.value === "add") {
    productSelectedRows.value.forEach(selectedRow => {
      const index = productData.value.findIndex(
          product => product.id === selectedRow.id
      );
      if (index !== -1) {
        productData.value.splice(index, 1);
      }
    });
    productData.value = productData.value.filter(
      (item) => !productSelectedRows.value.includes(item)
    );
    productSelectedRows.value = [];
  } else {
    let ids = [];
    if (productSelectedRows.value.length > 0) {
      ids = productSelectedRows.value.map(item => item.id);
      ids = productSelectedRows.value.map((item) => item.id);
    }
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
        .then(() => {
          delProduct(ids).then(res => {
            proxy.$modal.msgSuccess("删除成功");
            closeProductDia();
            getSalesLedgerWithProducts({id: currentId.value, type: 1}).then(
                res => {
                  productData.value = res.productData;
                }
            );
          });
        })
        .catch(() => {
          proxy.$modal.msg("已取消");
      .then(() => {
        delProduct(ids).then((res) => {
          proxy.$modal.msgSuccess("删除成功");
          closeProductDia();
          getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then(
            (res) => {
              productData.value = res.productData;
            }
          );
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  }
};
// 关闭产品弹框
@@ -1820,15 +2089,15 @@
    cancelButtonText: "取消",
    type: "warning",
  })
      .then(() => {
        proxy.download("/sales/ledger/export", {}, "销售台账.xlsx");
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
    .then(() => {
      proxy.download("/sales/ledger/export", {}, "销售台账.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
/** 判断单个产品是否已发货(根据shippingStatus判断,已发货或审核通过不可编辑和删除) */
const isProductShipped = product => {
const isProductShipped = (product) => {
  if (!product) return false;
  const status = String(product.shippingStatus || "").trim();
  // 如果发货状态是"已发货"或"审核通过",则不可编辑和删除
@@ -1836,15 +2105,15 @@
};
/** 判断销售订单下是否存在已发货/发货完成的产品(不可删除) */
const hasShippedProducts = products => {
const hasShippedProducts = (products) => {
  if (!products || !products.length) return false;
  return products.some(p => {
  return products.some((p) => {
    const status = String(p.shippingStatus || "").trim();
    // 有发货日期或车牌号视为已发货
    if (p.shippingDate || p.shippingCarNumber) return true;
    // 已进行发货、发货完成、已发货 均不可删除
    return (
        status === "已进行发货" || status === "发货完成" || status === "已发货"
      status === "已进行发货" || status === "发货完成" || status === "已发货"
    );
  });
};
@@ -1856,22 +2125,22 @@
    return;
  }
  const unauthorizedRows = selectedRows.value.filter(
      row => !canDeleteLedger(row)
    (row) => !canDeleteLedger(row)
  );
  if (unauthorizedRows.length > 0) {
    proxy.$modal.msgWarning("当前登录用户不是录入人,不能删除该数据");
    return;
  }
  const ids = selectedRows.value.map(item => item.id);
  const ids = selectedRows.value.map((item) => item.id);
  // 检查是否有已进行发货或发货完成的销售订单,若有则不允许删除
  const cannotDeleteNames = [];
  for (const row of selectedRows.value) {
    let products =
        row.children && row.children.length > 0 ? row.children : null;
      row.children && row.children.length > 0 ? row.children : null;
    if (!products) {
      try {
        const res = await productList({salesLedgerId: row.id, type: 1});
        const res = await productList({ salesLedgerId: row.id, type: 1 });
        products = res.data || [];
      } catch {
        products = [];
@@ -1883,7 +2152,7 @@
  }
  if (cannotDeleteNames.length > 0) {
    proxy.$modal.msgWarning(
        "已进行发货或发货完成的销售订单不能删除:" + cannotDeleteNames.join("、")
      "已进行发货或发货完成的销售订单不能删除:" + cannotDeleteNames.join("、")
    );
    return;
  }
@@ -1893,19 +2162,19 @@
    cancelButtonText: "取消",
    type: "warning",
  })
      .then(() => {
        delLedger(ids).then(res => {
          proxy.$modal.msgSuccess("删除成功");
          getList();
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
    .then(() => {
      delLedger(ids).then((res) => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
      });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// 打印功能
const handlePrint = async () => {
  const handlePrint = async () => {
  if (selectedRows.value.length === 0) {
    proxy.$modal.msgWarning("请选择要打印的数据");
    return;
@@ -1963,282 +2232,288 @@
  // 构建打印内容
  let printContent = `
                                                    <!DOCTYPE html>
                                                    <html>
                                                    <head>
                                                      <meta charset="UTF-8">
                                                      <title>打印预览</title>
                                                      <style>
                                                        body {
                                                          margin: 0;
                                                          padding: 0;
                                                          font-family: "SimSun", serif;
                                                          background: white;
                                                        }
                                                                                                     .print-page {
                                                            width: 200mm;
                                                            height: 75mm;
                                                            padding: 10mm;
                                                            padding-left: 20mm;
                                                            background: white;
                                                            box-sizing: border-box;
                                                            page-break-after: always;
                                                            page-break-inside: avoid;
                                                          }
                                                         .print-page:last-child {
                                                           page-break-after: avoid;
                                                         }
                                                        .delivery-note {
                                                          width: 100%;
                                                          height: 100%;
                                                          font-size: 12px;
                                                          line-height: 1.2;
                                                          display: flex;
                                                          flex-direction: column;
                                                          color: #000;
                                                        }
                                                        .header {
                                                          text-align: center;
                                                          margin-bottom: 8px;
                                                        }
                                                        .company-name {
                                                          font-size: 18px;
                                                          font-weight: bold;
                                                          margin-bottom: 4px;
                                                        }
                                                        .document-title {
                                                          font-size: 16px;
                                                          font-weight: bold;
                                                        }
                                                        .info-section {
                                                          margin-bottom: 8px;
                                                          display: flex;
                                                          justify-content: space-between;
                                                          align-items: center;
                                                        }
                                                        .info-row {
                                                          line-height: 20px;
                                                        }
                                                        .label {
                                                          font-weight: bold;
                                                          width: 60px;
                                                          font-size: 12px;
                                                        }
                                                        .value {
                                                          margin-right: 20px;
                                                          min-width: 80px;
                                                          font-size: 12px;
                                                        }
                                                                 .table-section {
                                                                 margin-bottom: 40px;
                                                          //  flex: 0.6;
                                                         }
                                                        .product-table {
                                                          width: 100%;
                                                          border-collapse: collapse;
                                                          border: 1px solid #000;
                                                        }
                                                                 .product-table th, .product-table td {
                                                           border: 1px solid #000;
                                                           padding: 6px;
                                                           text-align: center;
                                                           font-size: 12px;
                                                           line-height: 1.4;
                                                         }
                                                        .product-table th {
                                                          font-weight: bold;
                                                        }
                                                        .total-value {
                                                          font-weight: bold;
                                                        }
                                                        .footer-section {
                                                          margin-top: auto;
                                                        }
                                                        .footer-row {
                                                          display: flex;
                                                          margin-bottom: 3px;
                                                          line-height: 22px;
                                                          justify-content: space-between;
                                                        }
                                                        .footer-item {
                                                          display: flex;
                                                          margin-right: 20px;
                                                        }
                                                        .footer-item .label {
                                                          font-weight: bold;
                                                          width: 80px;
                                                          font-size: 12px;
                                                        }
                                                        .footer-item .value {
                                                          min-width: 80px;
                                                          font-size: 12px;
                                                        }
                                                        .address-item .address-value {
                                                          min-width: 200px;
                                                        }
                                                        @media print {
                                                          body {
                                                            margin: 0;
                                                            padding: 0;
                                                          }
                                                                     .print-page {
                                                             margin: 0;
                                                             padding: 10mm;
                                                             /* padding-left: 20mm; */
                                                             page-break-inside: avoid;
                                                             page-break-after: always;
                                                           }
                                                           .print-page:last-child {
                                                             page-break-after: avoid;
                                                           }
                                                        }
                                                      </style>
                                                    </head>
                                                    <body>
                                                  `;
                                                                                  <!DOCTYPE html>
                                                                                  <html>
                                                                                  <head>
                                                                                    <meta charset="UTF-8">
                                                                                    <title>打印预览</title>
                                                                                    <style>
                                                                                      body {
                                                                                        margin: 0;
                                                                                        padding: 0;
                                                                                        font-family: "SimSun", serif;
                                                                                        background: white;
                                                                                      }
                                                                                                                                   .print-page {
                                                                                          width: 200mm;
                                                                                          height: 75mm;
                                                                                          padding: 10mm;
                                                                                          padding-left: 20mm;
                                                                                          background: white;
                                                                                          box-sizing: border-box;
                                                                                          page-break-after: always;
                                                                                          page-break-inside: avoid;
                                                                                        }
                                                                                       .print-page:last-child {
                                                                                         page-break-after: avoid;
                                                                                       }
                                                                                      .delivery-note {
                                                                                        width: 100%;
                                                                                        height: 100%;
                                                                                        font-size: 12px;
                                                                                        line-height: 1.2;
                                                                                        display: flex;
                                                                                        flex-direction: column;
                                                                                        color: #000;
                                                                                      }
                                                                                      .header {
                                                                                        text-align: center;
                                                                                        margin-bottom: 8px;
                                                                                      }
                                                                                      .company-name {
                                                                                        font-size: 18px;
                                                                                        font-weight: bold;
                                                                                        margin-bottom: 4px;
                                                                                      }
                                                                                      .document-title {
                                                                                        font-size: 16px;
                                                                                        font-weight: bold;
                                                                                      }
                                                                                      .info-section {
                                                                                        margin-bottom: 8px;
                                                                                        display: flex;
                                                                                        justify-content: space-between;
                                                                                        align-items: center;
                                                                                      }
                                                                                      .info-row {
                                                                                        line-height: 20px;
                                                                                      }
                                                                                      .label {
                                                                                        font-weight: bold;
                                                                                        width: 60px;
                                                                                        font-size: 12px;
                                                                                      }
                                                                                      .value {
                                                                                        margin-right: 20px;
                                                                                        min-width: 80px;
                                                                                        font-size: 12px;
                                                                                      }
                                                                                               .table-section {
                                                                                               margin-bottom: 40px;
                                                                                        //  flex: 0.6;
                                                                                       }
                                                                                      .product-table {
                                                                                        width: 100%;
                                                                                        border-collapse: collapse;
                                                                                        border: 1px solid #000;
                                                                                      }
                                                                                               .product-table th, .product-table td {
                                                                                         border: 1px solid #000;
                                                                                         padding: 6px;
                                                                                         text-align: center;
                                                                                         font-size: 12px;
                                                                                         line-height: 1.4;
                                                                                       }
                                                                                      .product-table th {
                                                                                        font-weight: bold;
                                                                                      }
                                                                                      .total-value {
                                                                                        font-weight: bold;
                                                                                      }
                                                                                      .footer-section {
                                                                                        margin-top: auto;
                                                                                      }
                                                                                      .footer-row {
                                                                                        display: flex;
                                                                                        margin-bottom: 3px;
                                                                                        line-height: 22px;
                                                                                        justify-content: space-between;
                                                                                      }
                                                                                      .footer-item {
                                                                                        display: flex;
                                                                                        margin-right: 20px;
                                                                                      }
                                                                                      .footer-item .label {
                                                                                        font-weight: bold;
                                                                                        width: 80px;
                                                                                        font-size: 12px;
                                                                                      }
                                                                                      .footer-item .value {
                                                                                        min-width: 80px;
                                                                                        font-size: 12px;
                                                                                      }
                                                                                      .address-item .address-value {
                                                                                        min-width: 200px;
                                                                                      }
                                                                                      @media print {
                                                                                        body {
                                                                                          margin: 0;
                                                                                          padding: 0;
                                                                                        }
                                                                                                   .print-page {
                                                                                           margin: 0;
                                                                                           padding: 10mm;
                                                                                           /* padding-left: 20mm; */
                                                                                           page-break-inside: avoid;
                                                                                           page-break-after: always;
                                                                                         }
                                                                                         .print-page:last-child {
                                                                                           page-break-after: avoid;
                                                                                         }
                                                                                      }
                                                                                    </style>
                                                                                  </head>
                                                                                  <body>
                                                                                `;
  // 为每条数据生成打印页面
  printData.value.forEach((item, index) => {
    printContent += `
                                                      <div class="print-page">
                                                        <div class="delivery-note">
                                                          <div class="header">
                                                            <div class="document-title">零售发货单</div>
                                                          </div>
                                                          <div class="info-section">
                                                            <div class="info-row">
                                                              <div>
                                                                <span class="label">发货日期:</span>
                                                                <span class="value">${formatDate(
        item.createTime
    )}</span>
                                                              </div>
                                                              <div>
                                                                <span class="label">客户名称:</span>
                                                                <span class="value">${
        item.customerName
    }</span>
                                                              </div>
                                                            </div>
                                                            <div class="info-row">
                                                              <span class="label">单号:</span>
                                                              <span class="value">${
        item.salesContractNo ||
        ""
    }</span>
                                                            </div>
                                                          </div>
                                                                                    <div class="print-page">
                                                                                      <div class="delivery-note">
                                                                                        <div class="header">
                                                                                          <div class="document-title">零售发货单</div>
                                                                                        </div>
                                                          <div class="table-section">
                                                            <table class="product-table">
                                                              <thead>
                                                                <tr>
                                                                  <th>产品名称</th>
                                                                  <th>规格型号</th>
                                                                  <th>单位</th>
                                                                  <th>单价</th>
                                                                  <th>零售数量</th>
                                                                  <th>零售金额</th>
                                                                </tr>
                                                              </thead>
                                                              <tbody>
                                                                ${
        item.products &&
        item.products
            .length > 0
            ? item.products
                .map(
                    product => `
                                                                    <tr>
                                                                      <td>${
                        product.productCategory ||
                        ""
                    }</td>
                                                                      <td>${
                        product.specificationModel ||
                        ""
                    }</td>
                                                                      <td>${
                        product.unit ||
                        ""
                    }</td>
                                                                      <td>${
                        product.taxInclusiveUnitPrice ||
                        "0"
                    }</td>
                                                                      <td>${
                        product.quantity ||
                        "0"
                    }</td>
                                                                      <td>${
                        product.taxInclusiveTotalPrice ||
                        "0"
                    }</td>
                                                                    </tr>
                                                                  `
                )
                .join("")
            : '<tr><td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td></tr>'
    }
                                                              </tbody>
                                                              <tfoot>
                                                                <tr>
                                                                  <td class="label">合计</td>
                                                                  <td class="total-value"></td>
                                                                  <td class="total-value"></td>
                                                                  <td class="total-value"></td>
                                                                  <td class="total-value">${getTotalQuantityForPrint(
        item.products
    )}</td>
                                                                  <td class="total-value">${getTotalAmountForPrint(
        item.products
    )}</td>
                                                                </tr>
                                                              </tfoot>
                                                            </table>
                                                          </div>
                                                                                        <div class="info-section">
                                                                                          <div class="info-row">
                                                                                            <div>
                                                                                              <span class="label">发货日期:</span>
                                                                                              <span class="value">${formatDate(
                                                                                                item.createTime
                                                                                              )}</span>
                                                                                            </div>
                                                                                            <div>
                                                                                              <span class="label">客户名称:</span>
                                                                                              <span class="value">${
                                                                                                item.customerName
                                                                                              }</span>
                                                                                            </div>
                                                                                          </div>
                                                                                          <div class="info-row">
                                                                                            <span class="label">单号:</span>
                                                                                            <span class="value">${
                                                                                              item.salesContractNo ||
                                                                                              ""
                                                                                            }</span>
                                                                                          </div>
                                                                                        </div>
                                                          <div class="footer-section">
                                                            <div class="footer-row">
                                                              <div class="footer-item">
                                                                <span class="label">收货电话:</span>
                                                                <span class="value"></span>
                                                              </div>
                                                              <div class="footer-item">
                                                                <span class="label">收货人:</span>
                                                                <span class="value"></span>
                                                              </div>
                                                              <div class="footer-item address-item">
                                                                <span class="label">收货地址:</span>
                                                                <span class="value address-value"></span>
                                                              </div>
                                                            </div>
                                                            <div class="footer-row">
                                                              <div class="footer-item">
                                                                <span class="label">操作员:</span>
                                                                <span class="value">${
        userStore.nickName ||
        "撕开前"
    }</span>
                                                              </div>
                                                              <div class="footer-item">
                                                                <span class="label">打印日期:</span>
                                                                <span class="value">${formatDateTime(
        new Date()
    )}</span>
                                                              </div>
                                                            </div>
                                                          </div>
                                                        </div>
                                                      </div>
                                                    `;
                                                                                        <div class="table-section">
                                                                                          <table class="product-table">
                                                                                            <thead>
                                                                                              <tr>
                                                                                                <th>产品名称</th>
                                                                                                <th>规格型号</th>
                                                                                                <th>单位</th>
                                                                                                <th>单价</th>
                                                                                                <th>零售数量</th>
                                                                                                <th>零售金额</th>
                                                                                              </tr>
                                                                                            </thead>
                                                                                            <tbody>
                                                                                              ${
                                                                                                item.products &&
                                                                                                item
                                                                                                  .products
                                                                                                  .length >
                                                                                                  0
                                                                                                  ? item.products
                                                                                                      .map(
                                                                                                        (
                                                                                                          product
                                                                                                        ) => `
                                                                                                  <tr>
                                                                                                    <td>${
                                                                                                      product.productCategory ||
                                                                                                      ""
                                                                                                    }</td>
                                                                                                    <td>${
                                                                                                      product.specificationModel ||
                                                                                                      ""
                                                                                                    }</td>
                                                                                                    <td>${
                                                                                                      product.unit ||
                                                                                                      ""
                                                                                                    }</td>
                                                                                                    <td>${
                                                                                                      product.taxInclusiveUnitPrice ||
                                                                                                      "0"
                                                                                                    }</td>
                                                                                                    <td>${
                                                                                                      product.quantity ||
                                                                                                      "0"
                                                                                                    }</td>
                                                                                                    <td>${
                                                                                                      product.taxInclusiveTotalPrice ||
                                                                                                      "0"
                                                                                                    }</td>
                                                                                                  </tr>
                                                                                                `
                                                                                                      )
                                                                                                      .join(
                                                                                                        ""
                                                                                                      )
                                                                                                  : '<tr><td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td></tr>'
                                                                                              }
                                                                                            </tbody>
                                                                                            <tfoot>
                                                                                              <tr>
                                                                                                <td class="label">合计</td>
                                                                                                <td class="total-value"></td>
                                                                                                <td class="total-value"></td>
                                                                                                <td class="total-value"></td>
                                                                                                <td class="total-value">${getTotalQuantityForPrint(
                                                                                                  item.products
                                                                                                )}</td>
                                                                                                <td class="total-value">${getTotalAmountForPrint(
                                                                                                  item.products
                                                                                                )}</td>
                                                                                              </tr>
                                                                                            </tfoot>
                                                                                          </table>
                                                                                        </div>
                                                                                        <div class="footer-section">
                                                                                          <div class="footer-row">
                                                                                            <div class="footer-item">
                                                                                              <span class="label">收货电话:</span>
                                                                                              <span class="value"></span>
                                                                                            </div>
                                                                                            <div class="footer-item">
                                                                                              <span class="label">收货人:</span>
                                                                                              <span class="value"></span>
                                                                                            </div>
                                                                                            <div class="footer-item address-item">
                                                                                              <span class="label">收货地址:</span>
                                                                                              <span class="value address-value"></span>
                                                                                            </div>
                                                                                          </div>
                                                                                          <div class="footer-row">
                                                                                            <div class="footer-item">
                                                                                              <span class="label">操作员:</span>
                                                                                              <span class="value">${
                                                                                                userStore.nickName ||
                                                                                                "撕开前"
                                                                                              }</span>
                                                                                            </div>
                                                                                            <div class="footer-item">
                                                                                              <span class="label">打印日期:</span>
                                                                                              <span class="value">${formatDateTime(
                                                                                                new Date()
                                                                                              )}</span>
                                                                                            </div>
                                                                                          </div>
                                                                                        </div>
                                                                                      </div>
                                                                                    </div>
                                                                                  `;
  });
  printContent += `
                                                    </body>
                                                    </html>
                                                  `;
                                                                                  </body>
                                                                                  </html>
                                                                                `;
  // 写入内容到新窗口
  printWindow.document.write(printContent);
@@ -2254,16 +2529,12 @@
  };
};
// 格式化日期
const formatDate = dateString => {
const formatDate = (dateString) => {
  if (!dateString) return getCurrentDate();
  const date = new Date(dateString);
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  return `${year}/${month}/${day}`;
  return dayjs(dateString).format("YYYY/MM/DD HH:mm:ss");
};
// 格式化日期时间
const formatDateTime = date => {
const formatDateTime = (date) => {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
@@ -2273,7 +2544,7 @@
  return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
};
// 计算产品总数量
const getTotalQuantity = products => {
const getTotalQuantity = (products) => {
  if (!products || products.length === 0) return "0";
  const total = products.reduce((sum, product) => {
    return sum + (parseFloat(product.quantity) || 0);
@@ -2282,7 +2553,7 @@
};
// 计算产品总金额
const getTotalAmount = products => {
const getTotalAmount = (products) => {
  if (!products || products.length === 0) return "0";
  const total = products.reduce((sum, product) => {
    return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
@@ -2291,7 +2562,7 @@
};
// 用于打印的计算函数
const getTotalQuantityForPrint = products => {
const getTotalQuantityForPrint = (products) => {
  if (!products || products.length === 0) return "0";
  const total = products.reduce((sum, product) => {
    return sum + (parseFloat(product.quantity) || 0);
@@ -2299,7 +2570,7 @@
  return total.toFixed(2);
};
const getTotalAmountForPrint = products => {
const getTotalAmountForPrint = (products) => {
  if (!products || products.length === 0) return "0";
  const total = products.reduce((sum, product) => {
    return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
@@ -2317,17 +2588,17 @@
  }
  // 含税总价计算
  productForm.value.taxInclusiveTotalPrice =
      proxy.calculateTaxIncludeTotalPrice(
          productForm.value.taxInclusiveUnitPrice,
          productForm.value.quantity
      );
    proxy.calculateTaxIncludeTotalPrice(
      productForm.value.taxInclusiveUnitPrice,
      productForm.value.quantity
    );
  if (productForm.value.taxRate) {
    // 不含税总价计算
    productForm.value.taxExclusiveTotalPrice =
        proxy.calculateTaxExclusiveTotalPrice(
            productForm.value.taxInclusiveTotalPrice,
            productForm.value.taxRate
        );
      proxy.calculateTaxExclusiveTotalPrice(
        productForm.value.taxInclusiveTotalPrice,
        productForm.value.taxRate
      );
  }
};
@@ -2350,10 +2621,10 @@
  // 如果有税率,计算不含税总价
  if (productForm.value.taxRate) {
    productForm.value.taxExclusiveTotalPrice =
        proxy.calculateTaxExclusiveTotalPrice(
            totalPrice,
            productForm.value.taxRate
        );
      proxy.calculateTaxExclusiveTotalPrice(
        totalPrice,
        productForm.value.taxRate
      );
  }
  isCalculating.value = false;
@@ -2368,7 +2639,7 @@
  if (isCalculating.value) return;
  const exclusiveTotalPrice = parseFloat(
      productForm.value.taxExclusiveTotalPrice
    productForm.value.taxExclusiveTotalPrice
  );
  const quantity = parseFloat(productForm.value.quantity);
  const taxRate = parseFloat(productForm.value.taxRate);
@@ -2386,7 +2657,7 @@
  // 计算含税单价 = 含税总价 / 数量
  productForm.value.taxInclusiveUnitPrice = (
      inclusiveTotalPrice / quantity
    inclusiveTotalPrice / quantity
  ).toFixed(2);
  isCalculating.value = false;
@@ -2415,10 +2686,10 @@
  // 如果有税率,计算不含税总价
  if (productForm.value.taxRate) {
    productForm.value.taxExclusiveTotalPrice =
        proxy.calculateTaxExclusiveTotalPrice(
            productForm.value.taxInclusiveTotalPrice,
            productForm.value.taxRate
        );
      proxy.calculateTaxExclusiveTotalPrice(
        productForm.value.taxInclusiveTotalPrice,
        productForm.value.taxRate
      );
  }
  isCalculating.value = false;
@@ -2447,10 +2718,10 @@
  // 如果有税率,计算不含税总价
  if (productForm.value.taxRate) {
    productForm.value.taxExclusiveTotalPrice =
        proxy.calculateTaxExclusiveTotalPrice(
            productForm.value.taxInclusiveTotalPrice,
            productForm.value.taxRate
        );
      proxy.calculateTaxExclusiveTotalPrice(
        productForm.value.taxInclusiveTotalPrice,
        productForm.value.taxRate
      );
  }
  isCalculating.value = false;
@@ -2465,7 +2736,7 @@
  if (isCalculating.value) return;
  const inclusiveTotalPrice = parseFloat(
      productForm.value.taxInclusiveTotalPrice
    productForm.value.taxInclusiveTotalPrice
  );
  const taxRate = parseFloat(productForm.value.taxRate);
@@ -2477,7 +2748,7 @@
  // 计算不含税总价
  productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate);
    proxy.calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate);
  isCalculating.value = false;
};
@@ -2485,7 +2756,7 @@
 * 获取发货状态文本
 * @param row 行数据
 */
const getShippingStatusText = row => {
const getShippingStatusText = (row) => {
  // 如果已发货(有发货日期或车牌号),显示"已发货"
  // if (row.shippingDate || row.shippingCarNumber) {
  //   return "已发货";
@@ -2508,6 +2779,7 @@
    审核拒绝: "审核拒绝",
    审核通过: "审核通过",
    已发货: "已发货",
    部分发货: "部分发货",
  };
  return statusTextMap[statusStr] || "待发货";
};
@@ -2516,7 +2788,7 @@
 * 获取发货状态标签类型(颜色)
 * @param row 行数据
 */
const getShippingStatusType = row => {
const getShippingStatusType = (row) => {
  // 如果已发货(有发货日期或车牌号),显示绿色
  if (row.shippingStatus === "已发货") {
    return "success";
@@ -2539,16 +2811,17 @@
    审核拒绝: "danger",
    审核通过: "success",
    已发货: "success",
    部分发货: "warning",
  };
  return typeTextMap[statusStr] || "info";
};
/**
 * 判断是否可以发货
 * 只有在产品状态是充足,发货状态是待发货和审核拒绝的时候才可以发货
 * 只有在产品状态是充足,发货状态是待发货、审批中、审核拒绝、部分发货的时候才可以发货
 * @param row 行数据
 */
const canShip = row => {
const canShip = (row) => {
  // 产品状态必须是充足(approveStatus === 1)
  if (row.approveStatus !== 1) {
    return false;
@@ -2557,51 +2830,66 @@
  // 获取发货状态
  const shippingStatus = row.shippingStatus;
  // 如果已发货(有发货日期或车牌号),不能再次发货
  // 如果已发货,不能再次发货
  if (shippingStatus === "已发货") {
    return false;
  }
  // 发货状态必须是"待发货"或"审核拒绝"
  // 发货状态必须是"待发货"、"审批中"、"审核拒绝"或"部分发货"
  const statusStr = shippingStatus ? String(shippingStatus).trim() : "";
  return statusStr === "待发货" || statusStr === "审核拒绝";
  return (
    statusStr === "待发货" ||
    statusStr === "审批中" ||
    statusStr === "审核拒绝" ||
    statusStr === "部分发货"
  );
};
// 打开附件弹窗
const recordId = ref(0)
const fileDialogVisible = ref(false)
const recordId = ref(0);
const fileDialogVisible = ref(false);
// 打开附件弹框
const openFileDialog = async (row) => {
  recordId.value = row.id
  fileDialogVisible.value = true
}
  recordId.value = row.id;
  fileDialogVisible.value = true;
};
// 打开发货弹框
const openDeliveryForm = async row => {
const openDeliveryForm = async (row) => {
  // 检查是否可以发货
  if (!canShip(row)) {
    proxy.$modal.msgWarning(
        "只有在产品状态是充足,发货状态是待发货或审核拒绝的时候才可以发货"
      "只有在产品状态是充足,发货状态是待发货、审批中、审核拒绝或部分发货的时候才可以发货"
    );
    return;
  }
  // 审批中时提示用户已有待审批的发货记录
  const statusStr = row.shippingStatus ? String(row.shippingStatus).trim() : "";
  if (statusStr === "审批中") {
    proxy.$modal.msgWarning("该产品存在待审批的发货记录,请注意避免重复提交");
  }
  currentDeliveryRow.value = row;
  const batchNoList = await getDeliveryBatchNoList(
      row.productModelId || row.modelId
    row.productModelId || row.modelId
  );
  deliveryForm.value = {
    shippingCarNumber: "",
    expressCompany: "",
    expressNumber: "",
    type: "货车",
    batchNo: [],
    batchNoList,
  };
  deliveryFileList.value = [];
  deliveryFormVisible.value = true;
};
// 提交发货表单
const submitDelivery = () => {
  proxy.$refs["deliveryFormRef"].validate(valid => {
  proxy.$refs["deliveryFormRef"].validate((valid) => {
    if (valid) {
      const selectedBatchRows = getSelectedDeliveryBatchRows();
      if (selectedBatchRows.length === 0) {
@@ -2609,25 +2897,45 @@
        return;
      }
      const totalDeliveryQuantity = selectedBatchRows.reduce(
          (sum, item) => sum + Number(item.deliveryQuantity || 0),
          0
        (sum, item) => sum + Number(item.deliveryQuantity || 0),
        0
      );
      const currentRowQuantity = Number(currentDeliveryRow.value?.quantity || 0);
      if (currentRowQuantity > 0 && totalDeliveryQuantity > currentRowQuantity) {
        proxy.$modal.msgWarning("批号发货总数不能超过当前产品数量");
      const currentRowNoQuantity = Number(
        currentDeliveryRow.value?.noQuantity || 0
      );
      if (
        currentRowNoQuantity > 0 &&
        totalDeliveryQuantity > currentRowNoQuantity
      ) {
        proxy.$modal.msgWarning("批号发货总数不能超过待发货数量");
        return;
      }
      // 保存当前展开的行ID,以便发货后重新加载子表格数据
      const currentExpandedKeys = [...expandedRowKeys.value];
      const salesLedgerId = currentDeliveryRow.value.salesLedgerId;
      deliveryForm.value.batchNo = selectedBatchRows.map(item => item.id);
      const productModelId = currentDeliveryRow.value.productModelId || currentDeliveryRow.value.modelId;
      deliveryForm.value.batchNo = selectedBatchRows.map((item) => item.id);
      const productModelId =
        currentDeliveryRow.value.productModelId ||
        currentDeliveryRow.value.modelId;
      addShippingInfo({
        salesLedgerId: salesLedgerId,
        salesLedgerProductId: currentDeliveryRow.value.id,
        type: deliveryForm.value.type,
        shippingCarNumber:
          deliveryForm.value.type === "货车"
            ? deliveryForm.value.shippingCarNumber
            : "",
        expressCompany:
          deliveryForm.value.type === "快递"
            ? deliveryForm.value.expressCompany
            : "",
        expressNumber:
          deliveryForm.value.type === "快递"
            ? deliveryForm.value.expressNumber
            : "",
        storageBlobDTOs: deliveryFileList.value || [],
        batchNo: deliveryForm.value.batchNo,
        batchNoDetailList: selectedBatchRows.map(item => ({
        batchNoDetailList: selectedBatchRows.map((item) => ({
          stockInventoryId: item.id,
          batchNo: item.batchNo,
          quantity: Number(item.deliveryQuantity || 0),
@@ -2641,16 +2949,16 @@
          // 如果之前有展开的行,重新加载这些行的子表格数据
          if (currentExpandedKeys.length > 0) {
            // 使用 Promise.all 并行加载所有展开行的子表格数据
            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) {
                      tableData.value[index].children = res.data;
                    }
            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) {
                    tableData.value[index].children = res.data;
                  }
                }
              );
            });
            Promise.all(loadPromises).then(() => {
@@ -2665,8 +2973,18 @@
};
// 关闭发货弹框
const handleDeliveryTypeChange = (val) => {
  if (val === "货车") {
    deliveryForm.value.expressCompany = "";
    deliveryForm.value.expressNumber = "";
  } else {
    deliveryForm.value.shippingCarNumber = "";
  }
};
const closeDeliveryDia = () => {
  proxy.resetForm("deliveryFormRef");
  deliveryFileList.value = [];
  deliveryFormVisible.value = false;
  currentDeliveryRow.value = null;
};
@@ -2678,7 +2996,7 @@
onMounted(() => {
  searchForm.salesContractNo = route.query.salesContractNo;
  getList();
  userListNoPage().then(res => {
  userListNoPage().then((res) => {
    userList.value = res.data;
  });
  getCurrentFactoryName();