src/views/salesManagement/salesLedger/index.vue
@@ -6,21 +6,17 @@
          <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.customerContractNo" 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-form-item>
        <el-form-item label="项目名称:">
          <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-form-item>
        <el-form-item label="产品大类:">
          <el-input v-model="searchForm.productCategory" placeholder="请输入" clearable prefix-icon="Search"
                    @change="handleQuery" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleQuery"> 搜索 </el-button>
@@ -50,72 +46,75 @@
              <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 === 0" type="info">未出库</el-tag>
                  <el-tag v-if="scope.row.approveStatus === 1" type="success">已出库</el-tag>
                  <el-tag v-if="scope.row.approveStatus === 2" type="warning">审核中</el-tag>
                  <el-tag v-if="scope.row.approveStatus === 3" type="success">审核成功</el-tag>
                  <el-tag v-if="scope.row.approveStatus === 4" type="danger">审核失败</el-tag>
                </template>
              </el-table-column>
              <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>
                    <el-tag v-else type="info">未发货</el-tag>
                  </div>
                </template>
              </el-table-column>
              <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>
                </template>
              </el-table-column>
              <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 Width="60px" label="操作" align="center">
                <template #default="scope">
                  <el-button :disabled="scope.row.approveStatus!==2 || scope.row.approveStatus!==5" link type="primary" size="small" @click="openDeliveryForm(scope.row)">发货</el-button>
                </template>
              </el-table-column>
            </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="customerContractNo" 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="approvalStatus" width="100" align="center" show-overflow-tooltip>
          <template #default="scope">
            <el-tag :type="getApprovalStatusType(scope.row.approvalStatus)" size="small">
              {{ approvalStatusText[scope.row.approvalStatus] || '未知状态' }}
            </el-tag>
          </template>
        </el-table-column>
        <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 fixed="right" label="操作" min-width="100" align="center">
        <el-table-column label="发货状态" prop="shippingStatus" width="140" align="center" show-overflow-tooltip />
        <el-table-column label="发货日期" prop="shippingDate" width="140" align="center" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" min-width="140" align="center">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">编辑</el-button>
<!--            <el-button link type="primary" size="small" @click="openForm('view', scope.row)">详情</el-button>-->
            <el-button
              link
              type="primary"
              size="small"
              @click="openForm('edit', scope.row)"
              :disabled="scope.row.approvalStatus === 3 && scope.row.entryPerson !== userStore.id"
            >编辑</el-button>
            <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">附件</el-button>
<!--            <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">发货</el-button>-->
            <el-button
              link
              type="primary"
              size="small"
              @click="openDeliveryForm(scope.row)"
              :disabled="scope.row.shippingStatus === '已发货'"
            >
              发货
            </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" />
    </div>
    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'" width="70%"
      @close="closeDia">
    <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">
            <!-- 报价单导入入口:放在表单顶部,选择后反显客户/业务员等 -->
<!--            <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">
@@ -124,7 +123,9 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="业务员:" prop="salesman">
              <el-select v-model="form.salesman" placeholder="请选择" clearable :disabled="operationType === 'view'">
              <el-select v-model="form.salesman"
                                     filterable
                         :reserve-keyword="false" placeholder="请选择" clearable :disabled="operationType === 'view'">
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
                  :value="item.nickName" />
              </el-select>
@@ -133,26 +134,14 @@
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="客户合同号:" prop="customerContractNo">
              <el-input v-model="form.customerContractNo" placeholder="请输入" clearable :disabled="operationType === 'view'"/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="客户名称:" prop="customerId">
              <el-select v-model="form.customerId" placeholder="请选择" clearable :disabled="operationType === 'view'">
              <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
                    item.customerName+'-'+item.customerType
                  }}
                </el-option>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="项目名称:" prop="projectName">
              <el-input v-model="form.projectName" placeholder="请输入" clearable :disabled="operationType === 'view'" />
            </el-form-item>
          </el-col>
               <el-col :span="12">
@@ -165,7 +154,10 @@
        <el-row :gutter="30">
               <el-col :span="12">
                  <el-form-item label="录入人:" prop="entryPerson">
                     <el-select v-model="form.entryPerson" placeholder="请选择" clearable @change="changs" disabled>
                     <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-select>
                  </el-form-item>
@@ -181,6 +173,51 @@
          <el-col :span="12">
            <el-form-item label="付款方式">
              <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="24">
            <el-form-item>
              <template #label>
                <div style="display: flex; align-items: center; justify-content: space-between; width: 100%;">
                  <span>审批人选择:</span>
                  <el-button v-if="operationType !== 'view'" type="primary" size="small" @click="addApproverNode" icon="Plus">新增节点</el-button>
                </div>
              </template>
              <div class="approver-nodes-container">
                <div
                  v-for="(node, index) in approverNodes"
                  :key="node.id"
                  class="approver-node-item"
                >
                  <div class="approver-node-header">
                    <span class="approver-node-label">审批节点 {{ index + 1 }}</span>
                    <el-button
                      v-if="approverNodes.length > 1 && operationType !== 'view'"
                      type="danger"
                      size="small"
                      text
                      @click="removeApproverNode(index)"
                      icon="Delete"
                    >删除</el-button>
                  </div>
                  <el-select
                    v-model="node.userId"
                    placeholder="请选择审批人"
                    filterable
                    style="width: 100%;"
                    :disabled="operationType === 'view'"
                  >
                    <el-option
                      v-for="user in userList"
                      :key="user.userId"
                      :label="user.nickName"
                      :value="user.userId"
                    />
                  </el-select>
                </div>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
@@ -239,8 +276,9 @@
          <el-button @click="closeDia">取消</el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" width="40%" @close="closeProductDia">
    </FormDialog>
    <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" width="40%"
      @close="closeProductDia">
      <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef">
        <el-row :gutter="30">
          <el-col :span="24">
@@ -270,17 +308,19 @@
          </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-select>
<!--                     <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-select>-->
              <el-input-number :step="1" :min="0" v-model="productForm.taxRate" style="width: 100%"
                               placeholder="请输入" clearable @change="calculateFromTaxRate" />
                  </el-form-item>
               </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice">
            <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" />
@@ -347,10 +387,10 @@
               <div v-for="(item, index) in printData" :key="index" class="print-page">
                  <div class="delivery-note">
                     <div class="header">
                        <div class="company-name">鼎诚瑞实业有限责任公司</div>
                        <div class="company-name">青海湟水峡农业发展有限公司</div>
                        <div class="document-title">零售发货单</div>
                     </div>
                     <div class="info-section">
                        <div class="info-row">
                           <div>
@@ -358,12 +398,15 @@
                              <span class="value">{{ formatDate(item.createTime) }}</span>
                           </div>
                           <div>
                              <span class="label">客户名称:</span>
                              <span class="value">{{ item.customerName || '张爱有' }}</span>
                              <span class="label">发货车牌号:</span>
                              <span class="value">{{ item.shippingCarNumber }}</span>
                           </div>
                        </div>
                        <div class="info-row">
                           <div>
                              <span class="label">客户名称:</span>
                              <span class="value">{{ item.customerName || '张爱有' }}</span>
                           </div>
                           <span class="label">单号:</span>
                           <span class="value">{{ item.salesContractNo }}</span>
                        </div>
@@ -448,6 +491,21 @@
         <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%"
                        @change="handleShippingTypeChange"
                     >
                        <el-option label="货车" value="货车" />
                        <el-option label="快递" value="快递" />
                     </el-select>
                  </el-form-item>
               </el-col>
            </el-row>
            <el-row :gutter="30">
               <el-col :span="24">
                  <el-form-item label="发货日期:" prop="shippingDate">
                     <el-date-picker
                        style="width: 100%"
@@ -462,7 +520,7 @@
               </el-col>
            </el-row>
            <el-row :gutter="30">
               <el-col :span="24">
               <el-col :span="24" v-if="deliveryForm.type === '货车'">
                  <el-form-item label="发货车牌号:" prop="shippingCarNumber">
                     <el-input
                        v-model="deliveryForm.shippingCarNumber"
@@ -471,16 +529,56 @@
                     />
                  </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">
          <el-col :span="24">
            <el-form-item label="审批人:" prop="approverId">
              <el-select v-model="deliveryForm.approverId" placeholder="请选择审批人" clearable :disabled="operationType === 'view'">
                <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
              </el-select>
            </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="发货图片:">
                        <el-upload
                           v-model:file-list="deliveryFileList"
                           :action="upload.url"
                           multiple
                           ref="deliveryFileUpload"
                           auto-upload
                           :headers="upload.headers"
                           :data="{ type: 9 }"
                           :before-upload="handleDeliveryBeforeUpload"
                           :on-error="handleDeliveryUploadError"
                           :on-success="handleDeliveryUploadSuccess"
                           :on-remove="handleDeliveryRemove"
                           list-type="picture-card"
                           :limit="9"
                           accept="image/png,image/jpeg,image/jpg"
                        >
                           <el-icon class="avatar-uploader-icon"><Plus /></el-icon>
                           <template #tip>
                              <div class="el-upload__tip">
                                 支持 jpg、jpeg、png 格式,最多上传 9 张,单张大小不超过 10MB
                              </div>
                           </template>
                        </el-upload>
                     </el-form-item>
                  </el-col>
               </el-row>
         </el-form>
         <template #footer>
            <div class="dialog-footer">
@@ -489,44 +587,63 @@
            </div>
         </template>
      </el-dialog>
    <FileListDialog ref="fileListRef" v-model="fileListDialogVisible" />
    <!-- 导入对话框 -->
    <el-dialog
      :title="importUpload.title"
      v-model="importUpload.open"
      width="400px"
      append-to-body
    >
      <el-upload
        ref="importUploadRef"
        :limit="1"
        accept=".xlsx, .xls"
        :headers="importUpload.headers"
        :action="importUpload.url"
        :disabled="importUpload.isUploading"
        :before-upload="importUpload.beforeUpload"
        :on-progress="importUpload.onProgress"
        :on-success="importUpload.onSuccess"
        :on-error="importUpload.onError"
        :on-change="importUpload.onChange"
        :auto-upload="false"
        drag
      >
        <el-icon class="el-icon--upload"><UploadFilled /></el-icon>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <template #tip>
          <div class="el-upload__tip text-center">
            <span>仅允许导入xls、xlsx格式文件。</span>
          </div>
        </template>
      </el-upload>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitImportFile" :loading="importUpload.isUploading">确 定</el-button>
          <el-button @click="importUpload.open = false">取 消</el-button>
        </div>
      </template>
    </el-dialog>
      <!-- 销售报价单选择对话框 -->
      <el-dialog
         v-model="quotationDialogVisible"
         title="选择销售报价单"
         width="80%"
         :close-on-click-modal="false"
         @close="resetQuotationSearch"
      >
         <div class="search_form" style="margin-bottom: 15px;">
            <el-form :model="quotationSearchForm" :inline="true">
               <el-form-item label="报价单号:">
                  <el-input v-model="quotationSearchForm.quotationNo" placeholder="请输入" clearable />
               </el-form-item>
               <el-form-item label="客户:">
                  <el-input v-model="quotationSearchForm.customer" placeholder="请输入" clearable />
               </el-form-item>
               <el-form-item>
                  <el-button type="primary" @click="fetchQuotationList">搜索</el-button>
                  <el-button @click="resetQuotationSearch">重置</el-button>
               </el-form-item>
            </el-form>
         </div>
         <el-table
            :data="quotationList"
            border
            v-loading="quotationLoading"
            height="400"
            style="width: 100%"
         >
            <el-table-column align="center" label="序号" type="index" width="60" />
            <el-table-column label="报价单号" prop="quotationNo"show-overflow-tooltip />
            <el-table-column label="客户" prop="customer" show-overflow-tooltip />
            <el-table-column label="业务员" prop="salesperson" show-overflow-tooltip />
            <el-table-column label="报价日期" prop="quotationDate" show-overflow-tooltip />
            <el-table-column label="状态" prop="status" width="100" align="center">
               <template #default="scope">
                  <el-tag v-if="scope.row.status === '通过'" type="success" size="small">已通过</el-tag>
                  <el-tag v-else type="info" size="small">{{ scope.row.status }}</el-tag>
               </template>
            </el-table-column>
            <el-table-column label="操作" width="100" align="center" fixed="right">
               <template #default="scope">
                  <el-button link type="primary" size="small" @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"
            style="margin-bottom: 15px;"
            @pagination="quotationPaginationChange"
         />
      </el-dialog>
    <FileList ref="fileListRef" />
  </div>
</template>
@@ -536,25 +653,29 @@
import {onMounted, ref, getCurrentInstance} from "vue";
import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
import { ElMessageBox, ElMessage } from "element-plus";
import { UploadFilled } from "@element-plus/icons-vue";
import { UploadFilled, Plus } from "@element-plus/icons-vue";
import useUserStore from "@/store/modules/user";
import { userListNoPage } from "@/api/system/user.js";
import FileList from "./fileList.vue";
import FileList from '@/views/salesManagement/salesLedger/fileList.vue';
import FormDialog from '@/components/Dialog/FormDialog.vue';
import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
import {
  ledgerListPage,
  productList,
  customerList,
  addOrUpdateSalesLedger,
  getSalesLedgerWithProducts,
  delLedger,
  addOrUpdateSalesLedgerProduct,
  delProduct,
  delLedgerFile, getProductInventory,
   ledgerListPage,
   productList,
   customerList,
   addOrUpdateSalesLedger,
   getSalesLedgerWithProducts,
   delLedger,
   addOrUpdateSalesLedgerProduct,
   delProduct,
   delLedgerFile, getProductInventory,
} from "@/api/salesManagement/salesLedger.js";
import { getQuotationDetail } from "@/api/salesManagement/salesQuotation.js";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import useFormData from "@/hooks/useFormData.js";
import dayjs from "dayjs";
import FileListDialog from "@/components/Dialog/FileListDialog.vue";
import { getCurrentDate } from "@/utils/index.js";
import {listCustomerPrivatePool} from "@/api/basicData/customerFile.js";
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
@@ -573,6 +694,17 @@
});
const total = ref(0);
const fileList = ref([]);
const deliveryFileList = ref([]);
// 审批人节点(仿采购台账审批人)
const approverNodes = ref([{ id: 1, userId: null }]);
let nextApproverId = 2;
const addApproverNode = () => {
  approverNodes.value.push({ id: nextApproverId++, userId: null });
};
const removeApproverNode = (index) => {
  approverNodes.value.splice(index, 1);
};
// 用户信息表单弹框数据
const operationType = ref("");
@@ -580,9 +712,8 @@
const data = reactive({
  searchForm: {
    customerName: "", // 客户名称
    customerContractNo: "", // 客户合同编号
    salesContractNo: "", // 销售合同编号
    projectName: "", // 项目名称
    productCategory: "", // 产品大类
    entryDate: null, // 录入日期
    entryDateStart: undefined,
    entryDateEnd: undefined,
@@ -590,9 +721,7 @@
  form: {
    salesContractNo: "",
    salesman: "",
    customerContractNo: "",
    customerId: "",
    projectName: "",
    entryPerson: "",
    entryDate: "",
    maintenanceTime: "",
@@ -602,15 +731,11 @@
  },
  rules: {
    salesman: [{ required: true, message: "请选择", trigger: "change" }],
    customerContractNo: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    customerId: [{ required: true, message: "请选择", trigger: "change" }],
    projectName: [{ required: true, message: "请输入", trigger: "blur" }],
    entryPerson: [{ required: true, message: "请选择", trigger: "change" }],
    entryDate: [{ required: true, message: "请选择", trigger: "change" }],
    executionDate: [{ required: true, message: "请选择", trigger: "change" }],
  },
    },
});
const { form, rules } = toRefs(data);
const { form: searchForm } = useFormData(data.searchForm);
@@ -641,14 +766,14 @@
    taxInclusiveUnitPrice: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    taxRate: [{ required: true, message: "请选择", trigger: "change" }],
    // taxRate: [{ required: true, message: "请选择", trigger: "change" }],
    taxInclusiveTotalPrice: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    taxExclusiveTotalPrice: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
    invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
    // invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
  },
});
const { productForm, productRules } = toRefs(productFormData);
@@ -664,77 +789,50 @@
const printPreviewVisible = ref(false);
const printData = ref([]);
// 报价单导入相关
const quotationDialogVisible = ref(false);
const quotationLoading = ref(false);
const quotationList = ref([]);
const quotationSearchForm = reactive({
   quotationNo: "",
   customer: "",
});
// 报价单弹框分页
const quotationPage = reactive({
   current: 1,
   size: 10,
   total: 0,
});
const selectedQuotation = ref(null);
// 发货相关
const deliveryFormVisible = ref(false);
const currentDeliveryRow = ref(null);
const deliveryFormData = reactive({
  deliveryForm: {
    type: "货车", // 货车, 快递
    shippingDate: "",
    shippingCarNumber: "",
    expressCompany: "",
    expressNumber: "", // 快递单号
    shippingImages: "", // 发货图片,多个用逗号分隔
  },
  deliveryRules: {
    type: [
      { required: true, message: "请选择发货类型", trigger: "change" }
    ],
    shippingDate: [
      { required: true, message: "请选择发货日期", trigger: "change" }
    ],
    shippingCarNumber: [
      { required: true, message: "请输入发货车牌号", trigger: "blur" }
      { validator: (_, value, callback) => validateShippingCarNumber(value, callback), trigger: "blur" }
    ],
    approverId:[
      {
        required: true,message: "",
      }
    ]
    expressCompany: [
      { validator: (_, value, callback) => validateExpressCompany(value, callback), trigger: "blur" }
    ],
  },
});
const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
// 导入相关
const importUploadRef = ref(null);
const importUpload = reactive({
  title: "导入销售台账",
  open: false,
  url: import.meta.env.VITE_APP_BASE_API + "/sales/ledger/import",
  headers: { Authorization: "Bearer " + getToken() },
  isUploading: false,
  beforeUpload: (file) => {
    const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls');
    const isLt10M = file.size / 1024 / 1024 < 10;
    if (!isExcel) {
      proxy.$modal.msgError("上传文件只能是 xlsx/xls 格式!");
      return false;
    }
    if (!isLt10M) {
      proxy.$modal.msgError("上传文件大小不能超过 10MB!");
      return false;
    }
    return true;
  },
  onChange: (file, fileList) => {
    console.log('文件状态改变', file, fileList);
  },
  onProgress: (event, file, fileList) => {
    console.log('上传中...', event.percent);
  },
  onSuccess: (response, file, fileList) => {
    console.log('上传成功', response, file, fileList);
    importUpload.isUploading = false;
    if (response.code === 200) {
      proxy.$modal.msgSuccess("导入成功");
      importUpload.open = false;
      if (importUploadRef.value) {
        importUploadRef.value.clearFiles();
      }
      getList();
    } else {
      proxy.$modal.msgError(response.msg || "导入失败");
    }
  },
  onError: (error, file, fileList) => {
    console.error('上传失败', error, file, fileList);
    importUpload.isUploading = false;
    proxy.$modal.msgError("导入失败,请重试");
  },
});
const changeDaterange = (value) => {
  if (value) {
@@ -750,7 +848,11 @@
// 查询列表
/** 搜索按钮操作 */
const handleQuery = () => {
  page.current = 1;
  // 只有在点击搜索按钮时才重置页码到第一页
  // 避免表单字段change事件干扰分页
  if (arguments.length === 0) {
    page.current = 1;
  }
   expandedRowKeys.value = [];
  getList();
};
@@ -759,9 +861,7 @@
  page.size = obj.limit;
  getList();
};
const getList =async () => {
  let userLists = await userListNoPage();
  userList.value = userLists.data;
const getList = () => {
  tableLoading.value = true;
  const { entryDate, ...rest } = searchForm;
  ledgerListPage({ ...rest, ...page })
@@ -779,12 +879,35 @@
};
// 获取产品大类tree数据
const getProductOptions = () => {
  productTreeList().then((res) => {
    productOptions.value = convertIdToValue(res);
  // 返回 Promise,便于在编辑产品时等待加载完成
  return productTreeList().then((res) => {
    // 兼容接口返回 { data: [] } 或直接返回数组
    const list = Array.isArray(res) ? res : (res?.data ?? []);
    productOptions.value = convertIdToValue(list);
    return productOptions.value;
  });
};
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
};
// 订单审批状态显示文本
const approvalStatusText = {
  1: "待审核",
  2: "审批中",
  3: "审批通过",
  4: "审批失败",
};
// 获取审批状态标签类型
const getApprovalStatusType = (status) => {
  const typeMap = {
    1: "info",      // 待审核 - 灰色
    2: "warning",   // 审批中 - 橙色
    3: "success",   // 审批通过 - 绿色
    4: "danger",    // 审批失败 - 红色
  };
  return typeMap[status] || "info";
};
// 获取tree子数据
const getModels = (value) => {
@@ -794,10 +917,12 @@
  });
};
const getProductModel = (value) => {
  console.log("value", 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;
    fetchQuotationPrice();
  } else {
    productForm.value.specificationModel = null;
    productForm.value.unit = null;
@@ -817,8 +942,30 @@
  }
  return null; // 没有找到节点,返回null
};
// 根据报价接口回填单价
const fetchQuotationPrice = async () => {
  // 需要客户类型、产品名称、规格
  const customer = customerOption.value.find((c) => c.id === form.value.customerId);
  const customerType = customer?.customerType || customer?.type;
  const productName = productForm.value.productCategory;
  const specification = productForm.value.specificationModel;
  try {
    const { data } = await getQuotationDetail({
      type: customerType,
      productName,
      specification,
    });
    const price = data;
    if (price !== null && price !== undefined) {
      productForm.value.taxInclusiveUnitPrice = Number(price);
      mathNum(); // 重新计算总价
    }
  } catch (error) {
    console.error("获取报价单价失败", error);
  }
};
function convertIdToValue(data) {
  if (!data || !Array.isArray(data)) return [];
  return data.map((item) => {
    const { id, children, ...rest } = item;
    const newItem = {
@@ -832,6 +979,19 @@
    return newItem;
  });
}
// 根据名称反查产品大类 id,便于仅存名称时的反显
function findNodeIdByLabel(nodes, label) {
  if (!label) return null;
  for (let i = 0; i < nodes.length; i++) {
    const node = nodes[i];
    if (node.label === label) return node.value;
    if (node.children && node.children.length > 0) {
      const found = findNodeIdByLabel(node.children, label);
      if (found !== null && found !== undefined) return found;
    }
  }
  return null;
}
// 表格选择数据
const handleSelectionChange = (selection) => {
  // 过滤掉子数据
@@ -842,31 +1002,23 @@
  productSelectedRows.value = selectedRows;
};
const expandedRowKeys = ref([]);
// 展开行(始终只展开一行)
const expandChange = (row) => {
  const rowKey = row.id;
  const isExpanded = expandedRowKeys.value.includes(rowKey);
  if (isExpanded) {
    // 当前行已展开 -> 收起
// 展开行
const expandChange = (row, expandedRows) => {
  if (expandedRows.length > 0) {
    expandedRowKeys.value = [];
    return;
  }
  // 展开当前行前,先收起其它行
  expandedRowKeys.value = [];
  try {
    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;
      }
      // 只保留当前这一行处于展开状态
      expandedRowKeys.value = [rowKey];
    });
  } catch (error) {
    console.log(error);
    try {
      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;
        }
        expandedRowKeys.value.push(row.id);
      });
    } catch (error) {
      console.log(error);
    }
  } else {
    expandedRowKeys.value = [];
  }
};
// 主表合计方法
@@ -890,17 +1042,39 @@
  operationType.value = type;
  form.value = {};
  productData.value = [];
  customerList().then((res) => {
    customerOption.value = res;
  });
  let userLists = await userListNoPage();
  userList.value = userLists.data;
   listCustomerPrivatePool({current: -1,size:-1}).then((res) => {
      customerOption.value = res.data.records;
   });
  form.value.entryPerson = userStore.id;
  if (type !== "add") {
  if (type === "add") {
    // 新增时设置录入日期为当天
    form.value.entryDate = getCurrentDate();
    // 签订日期默认为当天
    form.value.executionDate = getCurrentDate();
    // 新增时重置审批人节点
    approverNodes.value = [{ id: 1, userId: null }];
    nextApproverId = 2;
  } else {
    currentId.value = row.id;
    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.salesLedgerFiles;
      // 回显审批人节点
      if (res.approveUserIds) {
        const userIds = res.approveUserIds.split(",").filter(id => id);
        approverNodes.value = userIds.map((userId, index) => ({
          id: index + 1,
          userId: Number(userId)
        }));
        nextApproverId = userIds.length + 1;
      } else {
        approverNodes.value = [{ id: 1, userId: null }];
        nextApproverId = 2;
      }
    });
  }
  // let userAll = await userStore.getInfo()
@@ -911,6 +1085,103 @@
  // });
  form.value.entryDate = getCurrentDate(); // 设置默认录入日期为当前日期
  dialogFormVisible.value = true;
};
// 打开报价单选择弹窗(仅审批通过)
const openQuotationDialog = async () => {
   if (operationType.value === "view") return;
   quotationDialogVisible.value = true;
   // 打开弹窗时重置分页到第一页
   quotationPage.current = 1;
   // 先确保客户列表已加载,便于后续回填 customerId
   if (!customerOption.value || customerOption.value.length === 0) {
      try {
         listCustomerPrivatePool({current: -1,size:-1}).then((res) => {
            customerOption.value = res.data.records;
         });
      } catch (e) {
         // ignore,允许用户后续手动选择客户
      }
   }
   await fetchQuotationList();
};
const fetchQuotationList = async () => {
   quotationLoading.value = true;
   try {
      const params = {
         // 后端分页字段:current / size
         current: quotationPage.current,
         size: quotationPage.size,
         ...quotationSearchForm,
         status: "通过",
      };
      const res = await getQuotationList(params);
      quotationList.value = res?.data?.records || [];
      quotationPage.total = res?.data?.total || 0;
   } finally {
      quotationLoading.value = false;
   }
};
const resetQuotationSearch = async () => {
   quotationSearchForm.quotationNo = "";
   quotationSearchForm.customer = "";
   quotationPage.current = 1;
   await fetchQuotationList();
};
// 报价单弹框分页切换
const quotationPaginationChange = (obj) => {
   quotationPage.current = obj.page;
   quotationPage.size = obj.limit;
   fetchQuotationList();
};
// 选中报价单后回填到台账表单
const applyQuotation = (row) => {
   if (!row) return;
   selectedQuotation.value = row;
   // 业务员
   form.value.salesman = (row.salesperson || "").trim();
   // 客户名称 -> customerId
   const qCustomerName = String(row.customer || "").trim();
   const customer = (customerOption.value || []).find((c) => {
      const name = String(c.customerName || "").trim();
      return name === qCustomerName || name.includes(qCustomerName) || qCustomerName.includes(name);
   });
   if (customer?.id) {
      form.value.customerId = customer.id;
   } else {
      // 如果找不到,保留原值(允许用户手动选择/不打断已有输入)
      form.value.customerId = form.value.customerId || "";
   }
   // 产品信息映射:报价 products -> 台账 productData
   const products = Array.isArray(row.products) ? row.products : [];
   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);
      return {
         // 台账字段
         productCategory: p.product || p.productName || "",
         specificationModel: p.specification || "",
         unit: p.unit || "",
         quantity: quantity,
         taxRate: taxRate,
         taxInclusiveUnitPrice: unitPrice.toFixed(2),
         taxInclusiveTotalPrice: taxInclusiveTotalPrice,
         taxExclusiveTotalPrice: taxExclusiveTotalPrice,
         invoiceType: "增普票",
      };
   });
   quotationDialogVisible.value = false;
};
function changs(val) {
  console.log(val);
@@ -951,6 +1222,47 @@
    });
  }
}
// 发货图片上传前校检
function handleDeliveryBeforeUpload(file) {
  // 校检文件类型
  const isImage = file.type === 'image/png' || file.type === 'image/jpeg' || file.type === 'image/jpg';
  if (!isImage) {
    proxy.$modal.msgError("只能上传 jpg、jpeg、png 格式的图片!");
    return false;
  }
  // 校检文件大小
  const isLt10M = file.size / 1024 / 1024 < 10;
  if (!isLt10M) {
    proxy.$modal.msgError("上传图片大小不能超过 10MB!");
    return false;
  }
  proxy.$modal.loading("正在上传图片,请稍候...");
  return true;
}
// 发货图片上传失败
function handleDeliveryUploadError(err) {
  proxy.$modal.msgError("上传图片失败");
  proxy.$modal.closeLoading();
}
// 发货图片上传成功回调
function handleDeliveryUploadSuccess(res, file, uploadFiles) {
  proxy.$modal.closeLoading();
  if (res.code === 200) {
    file.tempId = res.data.tempId;
    proxy.$modal.msgSuccess("上传成功");
  } else {
    proxy.$modal.msgError(res.msg);
    proxy.$refs.deliveryFileUpload.handleRemove(file);
  }
}
// 移除发货图片
function handleDeliveryRemove(file) {
  // 从文件列表中移除
  const index = deliveryFileList.value.findIndex(item => item.uid === file.uid);
  if (index > -1) {
    deliveryFileList.value.splice(index, 1);
  }
}
// 提交表单
const submitForm = () => {
  proxy.$refs["formRef"].validate((valid) => {
@@ -962,12 +1274,21 @@
        proxy.$modal.msgWarning("请添加产品信息");
        return;
      }
      // 校验审批人是否已选择
      const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
      if (hasEmptyApprover) {
        proxy.$modal.msgWarning("请选择审批人");
        return;
      }
      let tempFileIds = [];
      if (fileList.value !== null && fileList.value.length > 0) {
        tempFileIds = fileList.value.map((item) => item.tempId);
      }
      form.value.tempFileIds = tempFileIds;
      form.value.type = 1;
      // 将审批人节点转换为逗号分隔的字符串
      const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
      form.value.approveUserIds = approveUserIds;
      addOrUpdateSalesLedger(form.value).then((res) => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
@@ -980,11 +1301,14 @@
const closeDia = () => {
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
  // 重置审批人节点
  approverNodes.value = [{ id: 1, userId: null }];
  nextApproverId = 2;
};
const productIndex = ref(0);
// 打开产品弹框
const openProductForm =async (type, row,index) => {
const openProductForm = async (type, row, index) => {
  productOperationType.value = type;
  productForm.value = {};
  proxy.resetForm("productFormRef");
@@ -997,6 +1321,27 @@
  if (type === "edit") {
    productForm.value = { ...row };
    productIndex.value = index;
    // 编辑时根据产品大类名称反查 tree 节点 id,并加载规格型号列表
    try {
      const options = productOptions.value && productOptions.value.length > 0
        ? productOptions.value
        : await getProductOptions();
      const categoryId = findNodeIdByLabel(options, productForm.value.productCategory);
      if (categoryId) {
        const models = await modelList({ id: categoryId });
        modelOptions.value = models || [];
        // 根据当前规格型号名称反查并设置 productModelId,便于下拉框显示已选值
        const currentModel = (modelOptions.value || []).find(
          (m) => m.model === productForm.value.specificationModel
        );
        if (currentModel) {
          productForm.value.productModelId = currentModel.id;
        }
      }
    } catch (e) {
      // 加载失败时保持可编辑,不中断弹窗
      console.error("加载产品规格型号失败", e);
    }
  }
  productFormVisible.value = true;
  getProductOptions();
@@ -1075,21 +1420,6 @@
  proxy.resetForm("productFormRef");
  productFormVisible.value = false;
};
// 导入
const handleImport = () => {
  importUpload.title = "导入销售台账";
  importUpload.open = true;
  if (importUploadRef.value) {
    importUploadRef.value.clearFiles();
  }
};
// 提交导入文件
const submitImportFile = () => {
  importUpload.isUploading = true;
  proxy.$refs["importUploadRef"].submit();
};
// 导出
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
@@ -1111,6 +1441,14 @@
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  // 检查是否有审核通过且维护人不是当前登录用户的数据
  const cannotDeleteRows = selectedRows.value.filter(
    (item) => item.approvalStatus === 3 && item.entryPerson !== userStore.id
  );
  if (cannotDeleteRows.length > 0) {
    proxy.$modal.msgWarning("审核通过且维护人不是当前登录用户的数据不可删除");
    return;
  }
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
@@ -1135,7 +1473,7 @@
      proxy.$modal.msgWarning("请选择要打印的数据");
      return;
   }
   // 显示加载状态
   proxy.$modal.loading("正在获取产品数据,请稍候...");
   
@@ -1326,7 +1664,7 @@
      <div class="print-page">
        <div class="delivery-note">
          <div class="header">
            <div class="company-name">鼎诚瑞实业有限责任公司</div>
            <div class="company-name">青海湟水峡农业发展有限公司</div>
            <div class="document-title">零售发货单</div>
          </div>
          
@@ -1338,7 +1676,7 @@
              </div>
              <div>
                <span class="label">客户名称:</span>
                <span class="value">${item.customerName || '张爱有'}</span>
                <span class="value">${item.customerName}</span>
              </div>
            </div>
            <div class="info-row">
@@ -1360,8 +1698,8 @@
                </tr>
              </thead>
              <tbody>
                ${item.products && item.products.length > 0 ?
                  item.products.map(product => `
                ${item.products && item.products.length > 0 ?
         item.products.map(product => `
                    <tr>
                      <td>${product.productCategory || ''}</td>
                      <td>${product.specificationModel || ''}</td>
@@ -1370,7 +1708,7 @@
                      <td>${product.quantity || '0'}</td>
                      <td>${product.taxInclusiveTotalPrice || '0'}</td>
                    </tr>
                  `).join('') :
                  `).join('') :
                  '<tr><td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td></tr>'
                }
              </tbody>
@@ -1455,219 +1793,227 @@
   const seconds = String(date.getSeconds()).padStart(2, "0");
   return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
};
// 获取当前日期并格式化为 YYYY-MM-DD
function getCurrentDate() {
  const today = new Date();
  const year = today.getFullYear();
  const month = String(today.getMonth() + 1).padStart(2, "0"); // 月份从0开始
  const day = String(today.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}
// 计算产品总数量
const getTotalQuantity = (products) => {
  if (!products || products.length === 0) return '0';
  const total = products.reduce((sum, product) => {
    return sum + (parseFloat(product.quantity) || 0);
  }, 0);
  return total.toFixed(2);
   if (!products || products.length === 0) return '0';
   const total = products.reduce((sum, product) => {
      return sum + (parseFloat(product.quantity) || 0);
   }, 0);
   return total.toFixed(2);
};
// 计算产品总金额
const getTotalAmount = (products) => {
  if (!products || products.length === 0) return '0';
  const total = products.reduce((sum, product) => {
    return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
  }, 0);
  return total.toFixed(2);
   if (!products || products.length === 0) return '0';
   const total = products.reduce((sum, product) => {
      return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
   }, 0);
   return total.toFixed(2);
};
// 用于打印的计算函数
const getTotalQuantityForPrint = (products) => {
  if (!products || products.length === 0) return '0';
  const total = products.reduce((sum, product) => {
    return sum + (parseFloat(product.quantity) || 0);
  }, 0);
  return total.toFixed(2);
   if (!products || products.length === 0) return '0';
   const total = products.reduce((sum, product) => {
      return sum + (parseFloat(product.quantity) || 0);
   }, 0);
   return total.toFixed(2);
};
const getTotalAmountForPrint = (products) => {
  if (!products || products.length === 0) return '0';
  const total = products.reduce((sum, product) => {
    return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
  }, 0);
  return total.toFixed(2);
   if (!products || products.length === 0) return '0';
   const total = products.reduce((sum, product) => {
      return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
   }, 0);
   return total.toFixed(2);
};
// 发货类型校验:货车时要求车牌,快递时要求快递公司
const validateShippingCarNumber = (value, callback) => {
  if (deliveryForm.value.type === "货车") {
    if (!value) return callback(new Error("请输入发货车牌号"));
  }
  callback();
};
const validateExpressCompany = (value, callback) => {
  if (deliveryForm.value.type === "快递") {
    if (!value) return callback(new Error("请输入快递公司"));
  }
  callback();
};
const mathNum = () => {
  console.log("productForm.value", productForm.value);
  if (!productForm.value.taxInclusiveUnitPrice) {
    return;
  }
  if (!productForm.value.quantity) {
    return;
  }
  // 含税总价计算
  productForm.value.taxInclusiveTotalPrice =
    proxy.calculateTaxIncludeTotalPrice(
      productForm.value.taxInclusiveUnitPrice,
      productForm.value.quantity
    );
  if (productForm.value.taxRate) {
    // 不含税总价计算
    productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
        productForm.value.taxInclusiveTotalPrice,
        productForm.value.taxRate
      );
  }
   console.log("productForm.value", productForm.value);
   if (!productForm.value.taxInclusiveUnitPrice) {
      return;
   }
   if (!productForm.value.quantity) {
      return;
   }
   // 含税总价计算
   productForm.value.taxInclusiveTotalPrice =
      proxy.calculateTaxIncludeTotalPrice(
         productForm.value.taxInclusiveUnitPrice,
         productForm.value.quantity
      );
   if (productForm.value.taxRate) {
      // 不含税总价计算
      productForm.value.taxExclusiveTotalPrice =
         proxy.calculateTaxExclusiveTotalPrice(
            productForm.value.taxInclusiveTotalPrice,
            productForm.value.taxRate
         );
   }
};
// 根据含税总价计算含税单价和数量
const calculateFromTotalPrice = () => {
  if (isCalculating.value) return;
  const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
  const quantity = parseFloat(productForm.value.quantity);
  const taxRate = Number(productForm.value.taxRate) || 0;
  if (!totalPrice || !quantity || quantity <= 0) {
    return;
  }
  isCalculating.value = true;
  // 计算含税单价 = 含税总价 / 数量
  productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
  // 如果有税率,计算不含税总价
  if (productForm.value.taxRate) {
    productForm.value.taxExclusiveTotalPrice =
  productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
        totalPrice,
        productForm.value.taxRate
          totalPrice,
          taxRate
      );
  }
  isCalculating.value = false;
};
// 根据不含税总价计算含税单价和数量
const calculateFromExclusiveTotalPrice = () => {
   if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
   }
   // if (!productForm.value.taxRate) {
   //    proxy.$modal.msgWarning("请先选择税率");
   //    return;
   // }
  if (isCalculating.value) return;
  const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice);
  const quantity = parseFloat(productForm.value.quantity);
  const taxRate = parseFloat(productForm.value.taxRate);
  if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
  const taxRate = Number(productForm.value.taxRate) || 0;
  // if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
  //   return;
  // }
  if (!exclusiveTotalPrice || !quantity || quantity <= 0) {
    return;
  }
  isCalculating.value = true;
  // 先计算含税总价 = 不含税总价 / (1 - 税率/100)
  const taxRateDecimal = taxRate / 100;
  const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
  productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
  // 计算含税单价 = 含税总价 / 数量
  productForm.value.taxInclusiveUnitPrice = (inclusiveTotalPrice / quantity).toFixed(2);
  isCalculating.value = false;
};
// 根据数量变化计算总价
const calculateFromQuantity = () => {
   if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
   }
   // if (!productForm.value.taxRate) {
   //    proxy.$modal.msgWarning("请先选择税率");
   //    return;
   // }
  if (isCalculating.value) return;
  const quantity = parseFloat(productForm.value.quantity);
  const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
  const taxRate = Number(productForm.value.taxRate) || 0;
  if (!quantity || quantity <= 0 || !unitPrice) {
    return;
  }
  isCalculating.value = true;
  // 计算含税总价
  productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
  // 如果有税率,计算不含税总价
  if (productForm.value.taxRate) {
    productForm.value.taxExclusiveTotalPrice =
  productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
        productForm.value.taxInclusiveTotalPrice,
        productForm.value.taxRate
          productForm.value.taxInclusiveTotalPrice,
          taxRate
      );
  }
  isCalculating.value = false;
};
// 根据含税单价变化计算总价
const calculateFromUnitPrice = () => {
   if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
   }
   // if (!productForm.value.taxRate) {
   //    proxy.$modal.msgWarning("请先选择税率");
   //    return;
   // }
  if (isCalculating.value) return;
  const quantity = parseFloat(productForm.value.quantity);
  const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
  const taxRate = Number(productForm.value.taxRate) || 0;
  if (!quantity || quantity <= 0 || !unitPrice) {
    return;
  }
  isCalculating.value = true;
  // 计算含税总价
  productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
  // 如果有税率,计算不含税总价
  if (productForm.value.taxRate) {
    productForm.value.taxExclusiveTotalPrice =
  productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(
        productForm.value.taxInclusiveTotalPrice,
        productForm.value.taxRate
          productForm.value.taxInclusiveTotalPrice,
          taxRate
      );
  }
  isCalculating.value = false;
};
// 根据税率变化计算不含税总价
const calculateFromTaxRate = () => {
   if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
   }
   // if (!productForm.value.taxRate) {
   //    proxy.$modal.msgWarning("请先选择税率");
   //    return;
   // }
  if (isCalculating.value) return;
  const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
  const taxRate = parseFloat(productForm.value.taxRate);
  if (!inclusiveTotalPrice || !taxRate) {
  const taxRate = Number(productForm.value.taxRate) || 0;
  // if (!inclusiveTotalPrice || !taxRate) {
  //   return;
  // }
  if (!inclusiveTotalPrice) {
    return;
  }
  isCalculating.value = true;
  // 计算不含税总价
  productForm.value.taxExclusiveTotalPrice =
    proxy.calculateTaxExclusiveTotalPrice(
      inclusiveTotalPrice,
      taxRate
    );
  isCalculating.value = false;
};
/**
@@ -1676,7 +2022,6 @@
 * @param row 下载文件的相关信息对象
 */
const fileListRef = ref(null)
const fileListDialogVisible = ref(false);
const downLoadFile = (row) => {
  getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
    fileListRef.value.open(res.salesLedgerFiles)
@@ -1685,30 +2030,40 @@
// 打开发货弹框
const openDeliveryForm = (row) => {
  currentDeliveryRow.value = row;
   currentDeliveryRow.value = row;
  deliveryForm.value = {
    shippingDate: "", // 移除默认值设置
    type: "货车",
    shippingDate: getCurrentDate(),
    shippingCarNumber: "",
    expressCompany: "",
    expressNumber: "", // 初始化快递单号为空
    shippingImages: "", // 初始化图片为空
  };
  deliveryFormVisible.value = true;
  deliveryFileList.value = []; // 初始化文件列表为空
   deliveryFormVisible.value = true;
};
// 提交发货表单
const submitDelivery = () => {
  proxy.$refs["deliveryFormRef"].validate((valid) => {
    if (valid) {
      let tempFileIds = [];
      if (deliveryFileList.value !== null && deliveryFileList.value.length > 0) {
        tempFileIds = deliveryFileList.value.map((item) => item.tempId);
      }
      addShippingInfo({
        approverId:deliveryForm.value.approverId,
        salesLedgerId: currentDeliveryRow.value.salesLedgerId,
        salesLedgerProductId: currentDeliveryRow.value.id,
        salesLedgerId: currentDeliveryRow.value.id,
        type: deliveryForm.value.type,
        shippingDate: deliveryForm.value.shippingDate,
        shippingCarNumber: deliveryForm.value.shippingCarNumber,
        shippingCarNumber: deliveryForm.value.type === "货车" ? deliveryForm.value.shippingCarNumber : "",
        expressCompany: deliveryForm.value.type === "快递" ? deliveryForm.value.expressCompany : "",
        expressNumber: deliveryForm.value.type === "快递" ? deliveryForm.value.expressNumber : "",
        tempFileIds: tempFileIds,
      })
        .then(() => {
          proxy.$modal.msgSuccess("发货成功");
          closeDeliveryDia();
          getList();
          expandedRowKeys.value = [];
        })
        .catch(() => {
          proxy.$modal.msgError("发货失败,请重试");
@@ -1720,8 +2075,21 @@
// 关闭发货弹框
const closeDeliveryDia = () => {
  proxy.resetForm("deliveryFormRef");
  deliveryFileList.value = []; // 清空文件列表
  deliveryForm.value.shippingImages = ""; // 清空图片
  deliveryForm.value.expressNumber = ""; // 清空快递单号
  deliveryFormVisible.value = false;
  currentDeliveryRow.value = null;
};
// 发货类型切换时清空对应字段
const handleShippingTypeChange = (val) => {
  if (val === "货车") {
    deliveryForm.value.expressCompany = "";
    deliveryForm.value.expressNumber = "";
  } else {
    deliveryForm.value.shippingCarNumber = "";
  }
};
onMounted(() => {
@@ -1731,17 +2099,33 @@
<style scoped lang="scss">
.ml-10 {
  margin-left: 10px;
   margin-left: 10px;
}
:deep(.yellow) {
  background-color: #FAF0DE;
}
:deep(.pink) {
  background-color: #FAE1DE;
}
:deep(.red) {
  background-color: #FAE1DE;
}
:deep(.purple){
  background-color: #F4DEFA;
}
.table_list {
  margin-top: unset;
   margin-top: unset;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
   display: flex;
   justify-content: space-between;
   margin-bottom: 10px;
}
.print-preview-dialog {
   .el-dialog__body {
@@ -1909,4 +2293,62 @@
      page-break-after: avoid;
   }
}
// 隐藏图片上传组件的预览按钮(放大镜)
:deep(.el-upload-list--picture-card .el-upload-list__item-actions) {
  .el-upload-list__item-preview {
    display: none;
  }
}
// 审批人节点样式
.approver-nodes-container {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  padding: 16px;
  background-color: #f8f9fa;
  border-radius: 4px;
  border: 1px solid #e4e7ed;
}
.approver-node-item {
  flex: 0 0 calc(33.333% - 12px);
  min-width: 200px;
  padding: 12px;
  background-color: #fff;
  border-radius: 4px;
  border: 1px solid #dcdfe6;
  transition: all 0.3s;
  &:hover {
    border-color: #409eff;
    box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
  }
}
.approver-node-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}
.approver-node-label {
  font-size: 13px;
  font-weight: 500;
  color: #606266;
}
@media (max-width: 1200px) {
  .approver-node-item {
    flex: 0 0 calc(50% - 8px);
  }
}
@media (max-width: 768px) {
  .approver-node-item {
    flex: 0 0 100%;
  }
}
</style>