spring
5 天以前 c7f90a3054ee56c3be7317a67d2b192b6509b3e7
fix: 采购销售订单需要审核
已添加1个文件
已修改8个文件
2141 ■■■■■ 文件已修改
src/api/procurementManagement/procurementLedger.js 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/salesLedger.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index.vue 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index6.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 782 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceRegistration/index.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/index.vue 1073 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/procurementLedger.js
@@ -57,7 +57,7 @@
    params: query,
  });
}
// æŸ¥è¯¢é‡‡è´­å°è´¦åˆ—表
export function purchaseListPage(query) {
  return request({
    url: "/purchase/ledger/listPage",
@@ -72,29 +72,11 @@
    method: "get",
  });
}
export function updateApprovalStatus(query) {
    return request({
        url: "/purchase/ledger/updateApprovalStatus",
        method: "post",
        data: query,
    });
}
// ä¿å­˜é‡‡è´­æ¨¡æ¿
// /purchase/ledger/addPurchaseTemplate
export function addPurchaseTemplate(data) {
// æ ¹æ®é‡‡è´­åˆåŒå·æŸ¥è¯¢è¯¦æƒ…
export function getPurchaseByCode(query) {
    return request({
        url: "/purchase/ledger/addPurchaseTemplate",
        method: "post",
        data: data,
    });
}
// æŸ¥è¯¢é‡‡è´­æ¨¡æ¿
// /purchase/ledger/getPurchaseTemplateList
export function getPurchaseTemplateList(query) {
    return request({
        url: "/purchase/ledger/getPurchaseTemplateList",
    url: "/purchase/ledger/getPurchaseByCode",
        method: "get",
        params: query,
    });
src/api/salesManagement/salesLedger.js
@@ -118,9 +118,10 @@
    });
}
export function judgmentInventory(query) {
// æ ¹æ®é”€å”®åˆåŒå·æŸ¥è¯¢é”€å”®è¯¦æƒ…
export function getSalesByCode(query) {
  return request({
    url: "/sales/product/judgmentInventory",
    url: "/sales/ledger/getSalesByCode",
     method: "get",
        params: query,
  });
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
@@ -32,7 +32,24 @@
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row>
                <!-- æŠ¥é”€é‡‘额(仅当 approveType ä¸º 4 æ—¶æ˜¾ç¤ºï¼‰ -->
                <el-row v-if="props.approveType == 4">
                    <el-col :span="24">
                        <el-form-item label="报销金额:" prop="price">
                            <el-input-number
                                v-model="form.price"
                                placeholder="请输入报销金额"
                                :min="0"
                                :precision="2"
                                :step="0.01"
                                style="width: 100%"
                                disabled
                                clearable
                            />
                        </el-form-item>
                    </el-col>
                </el-row>
                <el-row v-if="!isPurchaseApproval && !isSalesApproval">
                    <el-col :span="24">
                        <el-form-item label="审批事由:" prop="approveReason">
                            <el-input v-model="form.approveReason" placeholder="请输入" clearable type="textarea" disabled/>
@@ -73,6 +90,98 @@
                    </el-col>
                </el-row>
            </el-form>
      <div v-if="isPurchaseApproval" style="margin: 10px 0 18px;">
        <el-divider content-position="left">采购详情</el-divider>
        <el-skeleton :loading="purchaseLoading" animated>
          <template #template>
            <el-skeleton-item variant="h3" style="width: 30%" />
            <el-skeleton-item variant="text" style="width: 100%" />
            <el-skeleton-item variant="text" style="width: 100%" />
          </template>
          <template #default>
            <el-empty v-if="!purchaseDetail || !purchaseDetail.purchaseContractNumber" description="未查询到对应采购详情" />
            <template v-else>
              <el-descriptions :column="2" border>
                <el-descriptions-item label="采购合同号">{{ purchaseDetail.purchaseContractNumber }}</el-descriptions-item>
                <el-descriptions-item label="供应商名称">{{ purchaseDetail.supplierName }}</el-descriptions-item>
                <el-descriptions-item label="项目名称">{{ purchaseDetail.projectName }}</el-descriptions-item>
                <el-descriptions-item label="销售合同号">{{ purchaseDetail.salesContractNo }}</el-descriptions-item>
                <el-descriptions-item label="签订日期">{{ purchaseDetail.executionDate }}</el-descriptions-item>
                <el-descriptions-item label="录入日期">{{ purchaseDetail.entryDate }}</el-descriptions-item>
                <el-descriptions-item label="付款方式">{{ purchaseDetail.paymentMethod }}</el-descriptions-item>
                <el-descriptions-item label="合同金额" :span="2">
                  <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
                    Â¥{{ Number(purchaseDetail.contractAmount ?? 0).toFixed(2) }}
                  </span>
                </el-descriptions-item>
              </el-descriptions>
              <div style="margin-top: 20px;">
                <h4>产品明细</h4>
                <el-table :data="purchaseProducts" border style="width: 100%">
                  <el-table-column prop="productCategory" label="产品名称" />
                  <el-table-column prop="specificationModel" label="规格型号" />
                  <el-table-column prop="unit" label="单位" />
                  <el-table-column prop="quantity" label="数量" />
                  <el-table-column prop="taxInclusiveUnitPrice" label="含税单价">
                    <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template>
                  </el-table-column>
                  <el-table-column prop="taxInclusiveTotalPrice" label="含税总价">
                    <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template>
                  </el-table-column>
                </el-table>
              </div>
            </template>
          </template>
        </el-skeleton>
      </div>
      <div v-if="isSalesApproval" style="margin: 10px 0 18px;">
        <el-divider content-position="left">销售详情</el-divider>
        <el-skeleton :loading="salesLoading" animated>
          <template #template>
            <el-skeleton-item variant="h3" style="width: 30%" />
            <el-skeleton-item variant="text" style="width: 100%" />
            <el-skeleton-item variant="text" style="width: 100%" />
          </template>
          <template #default>
            <el-empty v-if="!salesDetail || !salesDetail.salesContractNo" description="未查询到对应销售详情" />
            <template v-else>
              <el-descriptions :column="2" border>
                <el-descriptions-item label="销售合同号">{{ salesDetail.salesContractNo }}</el-descriptions-item>
                <el-descriptions-item label="客户合同号">{{ salesDetail.customerContractNo }}</el-descriptions-item>
                <el-descriptions-item label="客户名称">{{ salesDetail.customerName }}</el-descriptions-item>
                <el-descriptions-item label="业务员">{{ salesDetail.salesman }}</el-descriptions-item>
                <el-descriptions-item label="项目名称">{{ salesDetail.projectName }}</el-descriptions-item>
                <el-descriptions-item label="付款方式">{{ salesDetail.paymentMethod }}</el-descriptions-item>
                <el-descriptions-item label="录入人">{{ salesEntryPersonDisplay }}</el-descriptions-item>
                <el-descriptions-item label="录入日期">{{ salesDetail.entryDate }}</el-descriptions-item>
                <el-descriptions-item label="签订日期">{{ salesDetail.executionDate }}</el-descriptions-item>
                <el-descriptions-item label="合同金额" :span="2">
                  <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
                    Â¥{{ Number(salesDetail.contractAmount ?? 0).toFixed(2) }}
                  </span>
                </el-descriptions-item>
              </el-descriptions>
              <div style="margin-top: 20px;">
                <h4>产品明细</h4>
                <el-table :data="salesProducts" border style="width: 100%">
                  <el-table-column prop="productCategory" label="产品名称" />
                  <el-table-column prop="specificationModel" label="规格型号" />
                  <el-table-column prop="unit" label="单位" />
                  <el-table-column prop="quantity" label="数量" />
                  <el-table-column prop="taxInclusiveUnitPrice" label="含税单价">
                    <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template>
                  </el-table-column>
                  <el-table-column prop="taxInclusiveTotalPrice" label="含税总价">
                    <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template>
                  </el-table-column>
                </el-table>
              </div>
            </template>
          </template>
        </el-skeleton>
      </div>
      <el-form :model="{ activities }" ref="formRef" label-position="top">
        <el-steps :active="getActiveStep()" finish-status="success" process-status="process" align-center direction="vertical">
          <el-step
@@ -146,13 +255,15 @@
</template>
<script setup>
import { getCurrentInstance, reactive, ref, toRefs } from "vue";
import { computed, getCurrentInstance, reactive, ref, toRefs } from "vue";
import vueEsign from "vue-esign";
import {
    approveProcessDetails,
    getDept,
    updateApproveNode
} from "@/api/collaborativeApproval/approvalProcess.js";
import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js";
import { getSalesByCode } from "@/api/salesManagement/salesLedger.js";
import useUserStore from "@/store/modules/user.js";
import {userListNoPageByTenantId} from "@/api/system/user.js";
import { WarningFilled, Edit, Check, MoreFilled } from '@element-plus/icons-vue'
@@ -167,6 +278,38 @@
const userStore = useUserStore()
const productOptions = ref([]);
const userList = ref([])
const purchaseLoading = ref(false)
const currentPurchase = ref({})
const isPurchaseApproval = computed(() => Number(props.approveType) === 5)
const salesLoading = ref(false)
const currentSales = ref({})
const isSalesApproval = computed(() => Number(props.approveType) === 6)
const purchaseDetail = computed(() => currentPurchase.value?.data || currentPurchase.value || {})
const purchaseProducts = computed(() => {
  const detail = purchaseDetail.value || {}
  return detail.productData || detail.products || detail.children || []
})
const salesDetail = computed(() => currentSales.value?.data || currentSales.value || {})
const salesProducts = computed(() => {
  const detail = salesDetail.value || {}
  return detail.productData || detail.products || detail.children || []
})
/** é”€å”®è¯¦æƒ…:录入人(接口可能只返 entryPerson ç”¨æˆ·ID,需用 userList åæŸ¥æ˜µç§°ï¼‰ */
const salesEntryPersonDisplay = computed(() => {
  const d = salesDetail.value || {}
  if (d.entryPersonName) return d.entryPersonName
  if (d.recorderName) return d.recorderName
  if (d.createByName) return d.createByName
  if (d.createUserName) return d.createUserName
  const id = d.entryPerson
  if (id != null && id !== "" && userList.value?.length) {
    const u = userList.value.find(
      (x) => x.userId == id || String(x.userId) === String(id)
    )
    if (u) return u.nickName
  }
  return id != null && id !== "" ? String(id) : "-"
})
const data = reactive({
    form: {
        approveTime: "",
@@ -185,6 +328,12 @@
const esign = ref(null);
const lineWidth = ref(0);
const lineColor = ref("#000000");
const props = defineProps({
    approveType: {
        type: [Number, String],
        default: 0
    }
})
// ä¸Šä¼ é…ç½®
const upload = reactive({
@@ -219,11 +368,40 @@
const openDialog = (type, row) => {
  operationType.value = type;
  dialogFormVisible.value = true;
  currentPurchase.value = {}
  currentSales.value = {}
    userListNoPageByTenantId().then((res) => {
        userList.value = res.data;
    });
    form.value = {...row}
    getProductOptions()
  if (isPurchaseApproval.value) {
    const purchaseContractNumber = row?.approveReason
    if (purchaseContractNumber) {
      purchaseLoading.value = true
      getPurchaseByCode({ purchaseContractNumber }).then((res) => {
        // å…¼å®¹åŽç«¯è¿”回 {code,data} æˆ–直接返回详情对象两种结构
        currentPurchase.value = res || {}
      }).catch(() => {
        proxy.$modal.msgError("查询采购详情失败")
      }).finally(() => {
        purchaseLoading.value = false
      })
    }
  }
  if (isSalesApproval.value) {
    const salesContractNo = row?.approveReason
    if (salesContractNo) {
      salesLoading.value = true
      getSalesByCode({ salesContractNo }).then((res) => {
        currentSales.value = res || {}
      }).catch(() => {
        proxy.$modal.msgError("查询销售详情失败")
      }).finally(() => {
        salesLoading.value = false
      })
    }
  }
  approveProcessDetails(row.approveId).then((res) => {
    activities.value = res.data
    // å¢žåŠ isApproval字段
@@ -330,6 +508,10 @@
const closeDia = () => {
  proxy.resetForm("formRef");
  dialogFormVisible.value = false;
  purchaseLoading.value = false
  currentPurchase.value = {}
  salesLoading.value = false
  currentSales.value = {}
  emit('close')
};
defineExpose({
src/views/collaborativeApproval/approvalProcess/index.vue
@@ -43,7 +43,7 @@
      ></PIMTable>
    </div>
    <info-form-dia ref="infoFormDia" @close="handleQuery" :approveType="approveType"></info-form-dia>
    <approval-dia ref="approvalDia" @close="handleQuery"></approval-dia>
    <approval-dia ref="approvalDia" @close="handleQuery" :approveType="approveType"></approval-dia>
    <FileList ref="fileListRef" />
  </div>
</template>
@@ -76,7 +76,8 @@
  },
});
const { searchForm } = toRefs(data);
const tableColumn = ref([
const tableColumn = computed(() => {
  const baseColumns = [
  {
    label: "审批状态",
    prop: "approveStatus",
@@ -96,12 +97,14 @@
      }
    },
    formatType: (params) => {
      if (params === 0) {
        if (params == 0) {
        return "warning";
      } else if (params === 2) {
        } else if (params == 1) {
          return "primary";
        } else if (params == 2) {
        return "success";
      } else if (params === 3) {
        return "danger";
        } else if (params == 4) {
          return "";
      } else {
        return 'danger';
      }
@@ -141,8 +144,27 @@
    label: "当前审批人",
    prop: "approveUserCurrentName",
    width: 120
  },
  {
    }
  ];
  // å¦‚果是报销管理审批表(approveType=4),添加报销金额列
  if (props.approveType == 4) {
    baseColumns.push({
      label: "报销金额",
      prop: "price",
      width: 120,
      fixed: "right",
      formatData: (params) => {
        if (params) {
          return `Â¥${Number(params).toFixed(2)}`;
        }
        return '-'
      }
    });
  }
  // æ·»åŠ æ“ä½œåˆ—
  baseColumns.push({
    dataType: "action",
    label: "操作",
    align: "center",
@@ -180,8 +202,10 @@
        },
      },
    ],
  },
]);
  });
  return baseColumns;
});
const tableData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
@@ -239,6 +263,7 @@
    3: "出差管理审批表",
    4: "报销管理审批表",
    5: "采购申请审批表",
    6: "销售订单审批表",
  }
  const fileName = nameMap[type] || nameMap[0]
  proxy.download(url, {}, `${fileName}.xlsx`)
src/views/collaborativeApproval/approvalProcess/index6.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
<template>
  <div class="container">
    <!-- å¼•å…¥index.vue组件并传递参数 -->
    <ApprovalProcessIndex :approveType="6" />
  </div>
</template>
<script setup>
  import ApprovalProcessIndex from "./index.vue";
  // å®šä¹‰ç»„件名称
  defineOptions({
    name: "ApprovalProcessIndex1",
  });
</script>
<style scoped>
  .container {
    width: 100%;
    height: 100%;
  }
</style>
src/views/procurementManagement/invoiceEntry/index.vue
@@ -120,6 +120,7 @@
  gePurchaseListPage,
  {
    purchaseContractNumber: undefined,
    approvalStatus: 2
  },
  [
    {
src/views/procurementManagement/procurementLedger/index.vue
@@ -54,7 +54,6 @@
          :summary-method="summarizeMainTable"
          @expand-change="expandChange"
          height="calc(100vh - 18.5em)"
          :row-class-name="tableRowClassName"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column type="expand">
@@ -113,30 +112,35 @@
            prop="supplierName"
            show-overflow-tooltip
        />
        <el-table-column label="订单状态" width="100" align="center">
          <template #default="scope">
            <el-tag v-if="scope.row.isInvalid" type="danger" size="small">失效</el-tag>
            <el-tag v-else type="success" size="small">正常</el-tag>
          </template>
        </el-table-column>
        <el-table-column
            label="项目名称"
            prop="projectName"
            width="420"
            show-overflow-tooltip
        />
        <el-table-column
            label="审批状态"
            prop="approvalStatus"
            width="200"
            show-overflow-tooltip
        >
        <el-table-column label="审批状态" width="140">
          <template #default="scope">
            <el-tag
                size="small"
            >
              {{ approvalStatusText[scope.row.approvalStatus] || '未知状态' }}
            </el-tag>
              v-if="(scope.row.approveStatus ?? scope.row.approvalStatus ?? scope.row.auditStatus) == 0"
              type="warning"
            >待审核</el-tag>
            <el-tag
              v-else-if="(scope.row.approveStatus ?? scope.row.approvalStatus ?? scope.row.auditStatus) == 1"
              type="primary"
            >审核中</el-tag>
            <el-tag
              v-else-if="(scope.row.approveStatus ?? scope.row.approvalStatus ?? scope.row.auditStatus) == 2"
              type="success"
            >审核完成</el-tag>
            <el-tag
              v-else-if="(scope.row.approveStatus ?? scope.row.approvalStatus ?? scope.row.auditStatus) == 3"
              type="danger"
            >审核未通过</el-tag>
            <el-tag
              v-else-if="(scope.row.approveStatus ?? scope.row.approvalStatus ?? scope.row.auditStatus) == 4"
              type="info"
            >已重新提交</el-tag>
            <el-tag v-else type="info">-</el-tag>
          </template>
        </el-table-column>
        <el-table-column
@@ -246,8 +250,6 @@
                  v-model="form.supplierId"
                  placeholder="请选择"
                  clearable
                  filterable
                  allow-create
              >
                <el-option
                    v-for="item in supplierList"
@@ -294,21 +296,7 @@
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="审批人:" prop="approverId">
              <el-select
                  v-model="form.approverId"
                  placeholder="请选择审批人"
                  clearable
              >
                <el-option
                    v-for="item in userList"
                    :key="item.userId"
                    :label="item.nickName"
                    :value="item.userId"
                />
              </el-select>
            </el-form-item>
            <el-form-item label="录入人:" prop="recorderId" v-show="false">
            <el-form-item label="录入人:" prop="recorderId">
              <el-select
                  v-model="form.recorderId"
                  placeholder="请选择"
@@ -339,6 +327,48 @@
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item>
              <template #label>
                <span>审批人选择:</span>
                <el-button type="primary" @click="addApproverNode" style="margin-left: 8px;">新增节点</el-button>
              </template>
              <div style="display: flex; align-items: flex-end; flex-wrap: wrap;">
                <div
                  v-for="(node, index) in approverNodes"
                  :key="node.id"
                  style="margin-right: 30px; text-align: center; margin-bottom: 10px;"
                >
                  <div>
                    <span>审批人</span>
                    â†’
                  </div>
                  <el-select
                    v-model="node.userId"
                    placeholder="选择人员"
                    style="width: 140px; margin-bottom: 8px;"
                  >
                    <el-option
                      v-for="user in userList"
                      :key="user.userId"
                      :label="user.nickName"
                      :value="user.userId"
                    />
                  </el-select>
                  <div>
                    <el-button
                      type="danger"
                      size="small"
                      @click="removeApproverNode(index)"
                      v-if="approverNodes.length > 1"
                    >删除</el-button>
                  </div>
                </div>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-form-item label="产品信息:" prop="entryDate">
            <el-button type="primary" @click="openProductForm('add')"
            >添加</el-button
@@ -347,37 +377,6 @@
            >删除</el-button
            >
          </el-form-item>
          <div class="select-button-group" style="width: 220px; margin: 20px 0;" v-if="operationType === 'add'">
            <el-select
                filterable
                allow-create
                :reserve-keyword="true"
                :default-first-option="false"
                v-model="templateName"
                :input-value="filterInputValue"
                @filter-change="onTemplateFilterChange"
                @change="onTemplateChange"
                style="width: 180px; border-right: none; border-radius: 4px 0 0 4px;"
                placeholder="请选择"
                class="no-arrow-select"
            >
              <el-option
                  v-for="item in templateList"
                  :key="item.value"
                  :label="item.templateName"
                  :value="item.templateName"
              ></el-option>
            </el-select>
            <!-- æŒ‰é’®ï¼šä¸Ž Select é«˜åº¦åŒ¹é…ï¼ŒåŽ»æŽ‰å·¦ä¾§è¾¹æ¡†ï¼Œæ— ç¼è¡”æŽ¥ -->
            <el-button
                size="small"
                style="height: 32px; border-radius: 0 4px 4px 0; margin-left: -1px;"
                @click="handleButtonClick"
                :disabled="!templateName || templateName.trim() === '' || isTemplateNameDuplicate"
            >
              ä¿å­˜
            </el-button>
          </div>
        </el-row>
        <el-table
            :data="productData"
@@ -854,42 +853,35 @@
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import {getToken} from "@/utils/auth";
import pagination from "@/components/PIMTable/Pagination.vue";
import {getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs} from "vue";
import { ref, onMounted, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
import {Search} from "@element-plus/icons-vue";
import {ElMessage, ElMessageBox} from "element-plus";
import { ElMessageBox } from "element-plus";
import {userListNoPage} from "@/api/system/user.js";
import {
  addOrUpdateSalesLedgerProduct,
  delLedgerFile,
  delProduct,
  getProductInfoByContractNo,
  getSalesLedgerWithProducts,
  addOrUpdateSalesLedgerProduct,
  delProduct,
  delLedgerFile,
  getProductInfoByContractNo,
} from "@/api/salesManagement/salesLedger.js";
import {
  addOrEditPurchase,
  addPurchaseTemplate,
  createPurchaseNo,
  delPurchase,
  getOptions,
  getPurchaseById,
  getPurchaseTemplateList,
  getSalesNo,
  purchaseListPage,
  productList,
  purchaseListPage
  getPurchaseById,
  getOptions,
  createPurchaseNo,
} from "@/api/procurementManagement/procurementLedger.js";
import useFormData from "@/hooks/useFormData.js";
import QRCode from "qrcode";
import useUserStore from "@/store/modules/user";
import {modelList, productTreeList} from "@/api/basicData/product.js";
import dayjs from "dayjs";
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const productData = ref([]);
@@ -907,109 +899,17 @@
});
const total = ref(0);
const fileList = ref([]);
const approverNodes = ref([{ id: 1, userId: null }]);
let nextApproverId = 2;
import useUserStore from "@/store/modules/user";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import dayjs from "dayjs";
const userStore = useUserStore();
// äºŒç»´ç ç›¸å…³å˜é‡
const qrCodeDialogVisible = ref(false);
const qrCodeUrl = ref("");
// è®¢å•审批状态显示文本
const approvalStatusText = {
  0: '审批中',
  1: '审批通过',
  2: '审批失败'
};
const templateName = ref('');
const filterInputValue = ref('');
const templateList = ref([]);
const isTemplateNameDuplicate = ref(false); // æ ‡è®°æ¨¡æ¿åç§°æ˜¯å¦é‡å¤
// æ£€æŸ¥æ¨¡æ¿åç§°æ˜¯å¦é‡å¤
const checkTemplateNameDuplicate = (name) => {
  if (!name || name.trim() === '') {
    isTemplateNameDuplicate.value = false;
    return false;
  }
  const isDuplicate = templateList.value.some(item => item.templateName === name.trim());
  isTemplateNameDuplicate.value = isDuplicate;
  return isDuplicate;
};
// é˜²æŠ–定时器
let duplicateCheckTimer = null;
const onTemplateFilterChange = (val) => {
  filterInputValue.value = val ?? '';
  // æ¸…除之前的定时器
  if (duplicateCheckTimer) {
    clearTimeout(duplicateCheckTimer);
  }
  // å®žæ—¶æ£€æŸ¥æ¨¡æ¿åç§°æ˜¯å¦é‡å¤ï¼ˆé˜²æŠ–处理,避免频繁提示)
  if (val && val.trim()) {
    duplicateCheckTimer = setTimeout(() => {
      const isDuplicate = checkTemplateNameDuplicate(val);
      if (isDuplicate) {
        ElMessage({
          message: '模板名称已存在,请更换模板名称',
          type: 'warning',
          duration: 2000
        });
      }
    }, 300); // 300ms é˜²æŠ–
  } else {
    isTemplateNameDuplicate.value = false;
  }
};
// allow-create æ—¶ï¼Œè¾“入不存在的内容会作为 string å€¼è¿”回;这里同步回输入框以确保文字不丢
const onTemplateChange = async (val) => {
  if (typeof val === 'string') {
    filterInputValue.value = val;
    // é€‰æ‹©æˆ–输入时检查重复
    checkTemplateNameDuplicate(val);
  }
  // è¿‡æ»¤æ•°æ®ï¼ŒæŸ¥æ‰¾åŒ¹é…çš„æ¨¡æ¿
  const matchedTemplate = templateList.value.find(item => item.templateName === val);
  if (matchedTemplate?.id) {
    // å¦‚果找到模板,加载模板数据
    form.value = {
      ...form.value,
      ...matchedTemplate,
    };
    productData.value = matchedTemplate.productData || [];
    // ç”Ÿæˆæ–°çš„采购合同号
    try {
      const res = await createPurchaseNo();
      if (res?.data) {
        form.value.purchaseContractNumber = res.data;
      }
    } catch (error) {
      console.error('生成采购合同号失败:', error);
    }
  } else {
    // å¦‚果没有找到模板,重置表单(保持当前表单状态)
    const currentFormData = { ...form.value };
    const currentProductData = [...productData.value];
    // å¦‚果对话框未打开,先打开
    if (!dialogFormVisible.value) {
      operationType.value = 'add';
      dialogFormVisible.value = true;
    }
    // ç­‰å¾…下一个 tick åŽæ¢å¤æ•°æ®
    await nextTick();
    form.value = {
      ...form.value,
      ...currentFormData,
    };
    productData.value = currentProductData;
  }
};
// ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
const operationType = ref("");
@@ -1043,12 +943,18 @@
    projectName: [{ required: true, message: "请输入", trigger: "blur" }],
    supplierId: [{ required: true, message: "请输入", trigger: "blur" }],
    entryDate: [{ required: true, message: "请选择", trigger: "change" }],
    approverId:[{ required: true, message: "请选择审批人", trigger: "change" }],
    executionDate: [{ required: true, message: "请选择", trigger: "change" }],
  },
});
const {  form, rules } = toRefs(data);
const { form: searchForm } = useFormData(data.searchForm);
const addApproverNode = () => {
  approverNodes.value.push({ id: nextApproverId++, userId: null });
};
const removeApproverNode = (index) => {
  approverNodes.value.splice(index, 1);
};
// äº§å“è¡¨å•弹框数据
const productFormVisible = ref(false);
@@ -1109,97 +1015,13 @@
};
const formattedNumber = (row, column, cellValue) => {
  if (cellValue === null || cellValue === undefined || cellValue === '') {
    return '0.00';
  }
  const num = parseFloat(cellValue);
  if (isNaN(num)) {
    return '0.00';
  }
  return num.toFixed(2);
  return parseFloat(cellValue).toFixed(2);
};
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
  page.current = 1;
  getList();
};
// ä¿å­˜æ¨¡æ¿
const handleButtonClick = async () => {
  // æ£€æŸ¥æ¨¡æ¿åç§°æ˜¯å¦ä¸ºç©º
  if (!templateName.value || templateName.value.trim() === '') {
    ElMessage({
      message: '请输入模板名称',
      type: 'warning',
    });
    return;
  }
  // æ£€æŸ¥æ¨¡æ¿åç§°æ˜¯å¦é‡å¤
  const isDuplicate = checkTemplateNameDuplicate(templateName.value);
  if (isDuplicate) {
    ElMessage({
      message: '模板名称已存在,请更换模板名称',
      type: 'warning',
    });
    return;
  }
  // æ£€æŸ¥ä¾›åº”商是否选择
  if (!form.value.supplierId) {
    ElMessage({
      message: '请先选择供应商',
      type: 'warning',
    });
    return;
  }
  // æ£€æŸ¥æ˜¯å¦æœ‰äº§å“æ•°æ®
  // if (!productData.value || productData.value.length === 0) {
  //   ElMessage({
  //     message: '请先添加产品信息',
  //     type: 'warning',
  //   });
  //   return;
  // }
  try {
    let params = {
      productData: proxy.HaveJson(productData.value),
      supplierId: form.value.supplierId,
      paymentMethod: form.value.paymentMethod,
      recorderId: form.value.recorderId,
      approverId: form.value.approverId,
      templateName: templateName.value.trim()
    };
    console.log(params);
    let res = await addPurchaseTemplate(params);
    if (res && res.code === 200) {
      ElMessage({
        message: '模板保存成功',
        type: 'success',
      });
      // ä¿å­˜æˆåŠŸåŽé‡æ–°èŽ·å–æ¨¡æ¿åˆ—è¡¨
      await getTemplateList();
      // æ¸…空模板名称输入
      templateName.value = '';
      filterInputValue.value = '';
      isTemplateNameDuplicate.value = false;
    } else {
      ElMessage({
        message: res?.msg || '模板保存失败',
        type: 'error',
      });
    }
  } catch (error) {
    console.error('保存模板失败:', error);
    ElMessage({
      message: '模板保存失败,请稍后重试',
      type: 'error',
    });
  }
};
// å­è¡¨åˆè®¡æ–¹æ³•
const summarizeChildrenTable = (param) => {
@@ -1231,14 +1053,8 @@
  purchaseListPage({ ...rest, ...page })
      .then((res) => {
        tableLoading.value = false;
        // tableData.value = res.data.records;
        // å¤„理数据,添加失效状态标记
        tableData.value = res.data.records.map(record => ({
          ...record,
          isInvalid: record.isWhite === 1
        }));
        // åˆå§‹åŒ–子数据数组
        tableData.value.forEach((item) => {
      tableData.value = res.data.records;
      tableData.value.map((item) => {
          item.children = [];
        });
        total.value = res.data.total;
@@ -1257,24 +1073,19 @@
};
const expandedRowKeys = ref([]);
// å±•开行
const expandChange = async (row, expandedRows) => {
const expandChange = (row, expandedRows) => {
  if (expandedRows.length > 0) {
    expandedRowKeys.value = [];
    try {
      const res = await productList({ salesLedgerId: row.id, type: 2 });
      productList({ salesLedgerId: row.id, type: 2 }).then((res) => {
      const index = tableData.value.findIndex((item) => item.id === row.id);
      if (index > -1) {
        tableData.value[index].children = res.data || [];
          tableData.value[index].children = res.data;
        }
        expandedRowKeys.value.push(row.id);
      }
      });
    } catch (error) {
      console.error('加载产品列表失败:', error);
      proxy.$modal.msgError('加载产品列表失败');
      // å±•开失败时,移除展开状态
      const index = expandedRows.findIndex(item => item.id === row.id);
      if (index > -1) {
        expandedRows.splice(index, 1);
      }
      console.log(error);
    }
  } else {
    expandedRowKeys.value = [];
@@ -1293,63 +1104,53 @@
  ]);
};
// æ‰“开弹框
const openForm = async (type, row) => {
  await getTemplateList()
const openForm = (type, row) => {
  operationType.value = type;
  form.value = {};
  productData.value = [];
  fileList.value = [];
  templateName.value = '';
  filterInputValue.value = '';
  isTemplateNameDuplicate.value = false;
  try {
    // å¹¶è¡ŒåŠ è½½åŸºç¡€æ•°æ®
    const [userRes, salesRes, supplierRes] = await Promise.all([
      userListNoPage(),
      getSalesNo(),
      getOptions()
    ]);
    userList.value = userRes.data || [];
    salesContractList.value = salesRes || [];
    // ä¾›åº”商过滤出isWhite=0 çš„æ•°æ®
    supplierList.value = (supplierRes.data || []).filter((item) => item.isWhite === 0);
    // è®¾ç½®é»˜è®¤å€¼
  approverNodes.value = [{ id: 1, userId: null }];
  nextApproverId = 2;
  if (operationType.value == "add") {
    createPurchaseNo().then((res) => {
      form.value.purchaseContractNumber = res.data;
    });
  }
  userListNoPage().then((res) => {
    userList.value = res.data;
  });
  getSalesNo().then((res) => {
    salesContractList.value = res;
  });
  getOptions().then((res) => {
    supplierList.value = res.data;
  });
    form.value.recorderId = userStore.id;
    form.value.entryDate = getCurrentDate();
    if (type === "add") {
      // æ–°å¢žæ—¶ç”Ÿæˆé‡‡è´­åˆåŒå·
      try {
        const purchaseNoRes = await createPurchaseNo();
        if (purchaseNoRes?.data) {
          form.value.purchaseContractNumber = purchaseNoRes.data;
        }
      } catch (error) {
        console.error('生成采购合同号失败:', error);
        proxy.$modal.msgWarning('生成采购合同号失败');
      }
    } else if (type === "edit" && row?.id) {
      // ç¼–辑时加载数据
  if (type === "edit") {
      currentId.value = row.id;
      try {
        const purchaseRes = await getPurchaseById({ id: row.id, type: 2 });
        form.value = { ...purchaseRes };
        productData.value = purchaseRes.productData || [];
        fileList.value = purchaseRes.salesLedgerFiles || [];
      } catch (error) {
        console.error('加载采购台账数据失败:', error);
        proxy.$modal.msgError('加载数据失败');
        return;
    getPurchaseById({ id: row.id, type: 2 }).then((res) => {
      form.value = { ...res };
      productData.value = form.value.productData;
      const approveUserIds = form.value.approveUserIds || form.value.approverIds;
      if (approveUserIds) {
        const ids = String(approveUserIds)
          .split(",")
          .map((id) => Number(id.trim()))
          .filter((id) => !Number.isNaN(id));
        if (ids.length > 0) {
          approverNodes.value = ids.map((id, idx) => ({ id: idx + 1, userId: id }));
          nextApproverId = ids.length + 1;
      }
    }
      if (form.value.salesLedgerFiles) {
        fileList.value = form.value.salesLedgerFiles;
      } else {
        fileList.value = [];
      }
    });
  }
    dialogFormVisible.value = true;
  } catch (error) {
    console.error('打开表单失败:', error);
    proxy.$modal.msgError('加载基础数据失败');
  }
};
// ä¸Šä¼ å‰æ ¡æ£€
function handleBeforeUpload(file) {
@@ -1378,57 +1179,49 @@
  }
}
// ç§»é™¤æ–‡ä»¶
async function handleRemove(file) {
  if (!file?.id) {
    return;
  }
function handleRemove(file) {
  console.log("handleRemove", file.id);
  if (file.size > 1024 * 1024 * 10) {
    // ä»…前端清理,不调用删除接口和提示
    return;
  }
  if (operationType.value === "edit" && file.id) {
    try {
      await delLedgerFile([file.id]);
  if (operationType.value === "edit") {
    let ids = [];
    ids.push(file.id);
    delLedgerFile(ids).then((res) => {
      proxy.$modal.msgSuccess("删除成功");
    } catch (error) {
      console.error('删除文件失败:', error);
      proxy.$modal.msgError("删除文件失败");
    }
    });
  }
}
// æäº¤è¡¨å•
const submitForm = async () => {
  try {
    const valid = await proxy.$refs["formRef"].validate().catch(() => false);
    if (!valid) {
const submitForm = () => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      const hasEmptyApprover = approverNodes.value.some((node) => !node.userId);
      if (hasEmptyApprover) {
        proxy.$modal.msgWarning("请为所有审批节点选择审批人");
      return;
    }
    if (!productData.value || productData.value.length === 0) {
      form.value.approveUserIds = approverNodes.value.map((node) => node.userId).join(",");
      if (productData.value.length > 0) {
        form.value.productData = proxy.HaveJson(productData.value);
      } else {
      proxy.$modal.msgWarning("请添加产品信息");
      return;
    }
    form.value.productData = proxy.HaveJson(productData.value);
    form.value.tempFileIds = fileList.value
      .filter(item => item.tempId)
      .map((item) => item.tempId);
      let tempFileIds = [];
      if (fileList.value.length > 0) {
        tempFileIds = fileList.value.map((item) => item.tempId);
      }
      form.value.tempFileIds = tempFileIds;
    form.value.type = 2;
    try {
      await addOrEditPurchase(form.value);
      addOrEditPurchase(form.value).then((res) => {
      proxy.$modal.msgSuccess("提交成功");
      closeDia();
      getList();
    } catch (error) {
      console.error('提交表单失败:', error);
      proxy.$modal.msgError("提交失败,请稍后重试");
      });
    }
  } catch (error) {
    console.error('表单验证失败:', error);
  }
  });
};
// å…³é—­å¼¹æ¡†
const closeDia = () => {
@@ -1447,26 +1240,17 @@
  productFormVisible.value = true;
  getProductOptions();
};
const getProductOptions = async () => {
  try {
    const res = await productTreeList();
const getProductOptions = () => {
  productTreeList().then((res) => {
    productOptions.value = convertIdToValue(res);
  } catch (error) {
    console.error('加载产品选项失败:', error);
    proxy.$modal.msgError('加载产品选项失败');
  }
  });
};
const getModels = async (value) => {
const getModels = (value) => {
  if (value) {
    productForm.value.productCategory = findNodeById(productOptions.value, value) || "";
    try {
      const res = await modelList({ id: value });
      modelOptions.value = res || [];
    } catch (error) {
      console.error('加载规格型号失败:', error);
      proxy.$modal.msgError('加载规格型号失败');
      modelOptions.value = [];
    }
    modelList({ id: value }).then((res) => {
      modelOptions.value = res;
    });
  } else {
    productForm.value.productCategory = "";
    modelOptions.value = [];
@@ -1511,18 +1295,15 @@
  });
}
// æäº¤äº§å“è¡¨å•
const submitProduct = async () => {
  try {
    const valid = await proxy.$refs["productFormRef"].validate().catch(() => false);
    if (!valid) {
      return;
    }
const submitProduct = () => {
  proxy.$refs["productFormRef"].validate((valid) => {
    if (valid) {
    if (operationType.value === "edit") {
      await submitProductEdit();
        submitProductEdit();
    } else {
      if (productOperationType.value === "add") {
        productData.value.push({ ...productForm.value });
          console.log("productData.value---", productData.value);
      } else {
        productData.value[productOperationIndex.value] = {
          ...productForm.value,
@@ -1530,40 +1311,27 @@
      }
      closeProductDia();
    }
  } catch (error) {
    console.error('提交产品表单失败:', error);
  }
  });
};
const submitProductEdit = async () => {
  try {
const submitProductEdit = () => {
    productForm.value.salesLedgerId = currentId.value;
    productForm.value.type = 2;
    await addOrUpdateSalesLedgerProduct(productForm.value);
  addOrUpdateSalesLedgerProduct(productForm.value).then((res) => {
    proxy.$modal.msgSuccess("提交成功");
    closeProductDia();
    // é‡æ–°åŠ è½½äº§å“æ•°æ®
    try {
      const res = await getPurchaseById({ id: currentId.value, type: 2 });
      productData.value = res.productData || [];
    } catch (error) {
      console.error('重新加载产品数据失败:', error);
    }
  } catch (error) {
    console.error('提交产品编辑失败:', error);
    proxy.$modal.msgError("提交失败,请稍后重试");
  }
    getPurchaseById({ id: currentId.value, type: 2 }).then((res) => {
      productData.value = res.productData;
    });
  });
};
// åˆ é™¤äº§å“
const deleteProduct = async () => {
const deleteProduct = () => {
  if (productSelectedRows.value.length === 0) {
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  if (operationType.value === "add") {
    // æ–°å¢žæ¨¡å¼ä¸‹ï¼Œç›´æŽ¥ä»Žå‰ç«¯æ•°æ®ä¸­åˆ é™¤
    productSelectedRows.value.forEach((selectedRow) => {
      const index = productData.value.findIndex(
          (product) => product.id === selectedRow.id
@@ -1572,42 +1340,30 @@
        productData.value.splice(index, 1);
      }
    });
    proxy.$modal.msgSuccess("删除成功");
  } else {
    // ç¼–辑模式下,需要调用接口删除
    const ids = productSelectedRows.value
      .filter(item => item.id)
      .map((item) => item.id);
    if (ids.length === 0) {
      proxy.$modal.msgWarning("请选择有效的数据");
      return;
    let ids = [];
    if (productSelectedRows.value.length > 0) {
      ids = productSelectedRows.value.map((item) => item.id);
    }
    try {
      await ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除确认", {
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
      });
      await delProduct(ids);
    })
      .then(() => {
        delProduct(ids).then((res) => {
      proxy.$modal.msgSuccess("删除成功");
      closeProductDia();
      // é‡æ–°åŠ è½½äº§å“æ•°æ®
      try {
        const res = await getSalesLedgerWithProducts({ id: currentId.value, type: 2 });
        productData.value = res.productData || [];
      } catch (error) {
        console.error('重新加载产品数据失败:', error);
          getSalesLedgerWithProducts({ id: currentId.value, type: 2 }).then(
            (res) => {
              productData.value = res.productData;
      }
    } catch (error) {
      if (error !== 'cancel') {
        console.error('删除产品失败:', error);
        proxy.$modal.msgError("删除失败,请稍后重试");
      }
    }
          );
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  }
};
// å…³é—­äº§å“å¼¹æ¡†
@@ -1616,65 +1372,56 @@
  productFormVisible.value = false;
};
// å¯¼å‡º
const handleOut = async () => {
  try {
    await ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出确认", {
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    });
  })
    .then(() => {
    proxy.download("/purchase/ledger/export", {}, "采购台账.xlsx");
  } catch (error) {
    if (error !== 'cancel') {
      console.error('导出失败:', error);
      proxy.$modal.msgError("导出失败,请稍后重试");
    }
  }
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// åˆ é™¤
const handleDelete = async () => {
  if (selectedRows.value.length === 0) {
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
const handleDelete = () => {
  let ids = [];
  if (selectedRows.value.length > 0) {
  // æ£€æŸ¥æ˜¯å¦æœ‰ä»–人维护的数据
  const unauthorizedData = selectedRows.value.filter(item => item.recorderName !== userStore.nickName);
  if (unauthorizedData.length > 0) {
    proxy.$modal.msgWarning("不可删除他人维护的数据");
    return;
  }
  const ids = selectedRows.value
    .filter(item => item.id)
    .map((item) => item.id);
  if (ids.length === 0) {
    proxy.$modal.msgWarning("请选择有效的数据");
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning("请选择数据");
    return;
  }
  try {
    await ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除确认", {
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    });
    await delPurchase(ids);
  })
    .then(() => {
      delPurchase(ids).then((res) => {
    proxy.$modal.msgSuccess("删除成功");
    getList();
  } catch (error) {
    if (error !== 'cancel') {
      console.error('删除失败:', error);
      proxy.$modal.msgError("删除失败,请稍后重试");
    }
  }
      });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// èŽ·å–å½“å‰æ—¥æœŸå¹¶æ ¼å¼åŒ–ä¸º YYYY-MM-DD
function getCurrentDate() {
  return dayjs().format("YYYY-MM-DD");
  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 mathNum = () => {
  if (!productForm.value.taxRate) {
@@ -1741,7 +1488,9 @@
};
// é”€å”®åˆåŒé€‰æ‹©æ”¹å˜æ–¹æ³•
const salesLedgerChange = async (row) => {
  const index = salesContractList.value.findIndex((item) => item.id === row);
  console.log("row", row);
  var index = salesContractList.value.findIndex((item) => item.id == row);
  console.log("index", index);
  if (index > -1) {
    form.value.projectName = salesContractList.value[index].projectName;
    await querygProductInfoByContractNo();
@@ -1789,18 +1538,13 @@
    return;
  }
  try {
    const a = document.createElement('a');
    a.href = qrCodeUrl.value;
    a.download = `采购合同号二维码_${dayjs().format('YYYYMMDDHHmmss')}.png`;
  a.download = `采购合同号二维码_${new Date().getTime()}.png`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    proxy.$modal.msgSuccess("下载成功");
  } catch (error) {
    console.error('下载二维码失败:', error);
    proxy.$modal.msgError("下载失败,请稍后重试");
  }
};
// æ‰«ç æ–°å¢žå¯¹è¯æ¡†ç›¸å…³å˜é‡
@@ -1873,13 +1617,9 @@
};
// æäº¤æ‰«ç æ–°å¢ž
const submitScanAdd = async () => {
  try {
    const valid = await proxy.$refs["scanAddFormRef"].validate().catch(() => false);
    if (!valid) {
      return;
    }
const submitScanAdd = () => {
  proxy.$refs["scanAddFormRef"].validate((valid) => {
    if (valid) {
    // æž„建新增数据
    const newData = {
      purchaseContractNumber: scanAddForm.purchaseContractNumber,
@@ -1893,15 +1633,14 @@
      type: 2
    };
    // await addOrEditPurchase(newData);
      // æ¨¡æ‹Ÿæ–°å¢žæˆåŠŸ
    proxy.$modal.msgSuccess("扫码新增成功!");
    closeScanAddDialog();
    getList(); // åˆ·æ–°åˆ—表
  } catch (error) {
    console.error('提交扫码新增失败:', error);
    proxy.$modal.msgError("提交失败,请稍后重试");
      // å¯ä»¥é€‰æ‹©æ˜¯å¦åˆ·æ–°åˆ—表
      // getList();
  }
  });
};
// æ‰“开扫码登记对话框
@@ -1924,13 +1663,9 @@
};
// æäº¤æ‰«ç ç™»è®°
const submitScan = async () => {
  try {
    const valid = await proxy.$refs["scanFormRef"].validate().catch(() => false);
    if (!valid) {
      return;
    }
const submitScan = () => {
  proxy.$refs["scanFormRef"].validate((valid) => {
    if (valid) {
    // æ·»åŠ æ‰«ç è®°å½•
    scanRecords.value.push({
      ...scanForm,
@@ -1941,52 +1676,27 @@
    scanForm.scanRemark = scanForm.scanRemark || "无";
    proxy.$modal.msgSuccess("扫码登记成功!");
    closeScanDialog();
  } catch (error) {
    console.error('提交扫码登记失败:', error);
    proxy.$modal.msgError("提交失败,请稍后重试");
  }
  });
};
// èŽ·å–å½“å‰æ—¥æœŸæ—¶é—´
function getCurrentDateTime() {
  return dayjs().format("YYYY-MM-DD HH:mm:ss");
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, "0");
  const day = String(now.getDate()).padStart(2, "0");
  const hours = String(now.getHours()).padStart(2, "0");
  const minutes = String(now.getMinutes()).padStart(2, "0");
  const seconds = String(now.getSeconds()).padStart(2, "0");
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// æ·»åŠ è¡Œç±»åæ–¹æ³•
const tableRowClassName = ({ row }) => {
  return row.isInvalid ? 'invalid-row' : '';
};
// èŽ·å–æ¨¡æ¿ä¿¡æ¯
const getTemplateList =async ()=>{
  let res = await getPurchaseTemplateList()
  if(res && res.code===200 && Array.isArray(res.data)){
    templateList.value = res.data
  }
}
onMounted(() => {
  getList();
  getTemplateList();
});
</script>
<style scoped lang="scss">
.invalid-row {
  opacity: 0.6;
  background-color: #f5f7fa;
}
.el-row{
  justify-content: space-between;
  align-items: center
}
.no-arrow-select {
  --el-select-suffix-icon-color: transparent; /* éšè—é»˜è®¤ä¸‹æ‹‰ç®­å¤´ */
}
.select-button-group {
  display: flex;
  align-items: center;
}
</style>
<style scoped lang="scss"></style>
src/views/salesManagement/invoiceRegistration/index.vue
@@ -437,6 +437,7 @@
  searchForm: {
    customerName: "",
    status: false,
    approvalStatus: 2,
    customerContractNo: undefined, // å®¢æˆ·åˆåŒå·
    projectName: undefined, // é¡¹ç›®åç§°
    createUer: undefined, // ç™»è®°äºº
src/views/salesManagement/salesLedger/index.vue
@@ -1,48 +1,29 @@
<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"
          <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"
          <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"
          <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"
          <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>
@@ -50,228 +31,110 @@
      <div class="actions">
        <div></div>
        <div>
          <el-button type="primary"
                     @click="openForm('add')">
          <el-button type="primary" @click="openForm('add')">
            æ–°å¢žå°è´¦
          </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"
                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" />
      <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
        :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" 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" />
        <el-table-column type="expand">
          <template #default="props">
            <el-table :data="props.row.children"
                      border
                      show-summary
                      :summary-method="summarizeChildrenTable">
              <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="生产状态"
                               width="100px"
                               align="center">
                <template #default="scope">
                  <el-tag v-if="scope.row.productionStatus === '已完成'"
                          type="success">已完成</el-tag>
                  <el-tag v-if="scope.row.productionStatus === '生产中'"
                          type="warning">生产中</el-tag>
                  <el-tag v-if="scope.row.productionStatus === '未开始'"
                          type="danger">未开始</el-tag>
                  <el-tag v-if="!scope.row.productionStatus"
                          type="info">暂无状态</el-tag>
                </template>
              </el-table-column>
              <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 :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable" style="min-width: 1200px;"
                      scrollbar-always-on>
              <el-table-column align="center" label="序号" type="index" width="70" />
              <el-table-column label="产品大类" prop="productCategory" width="160" />
              <el-table-column label="规格型号" prop="specificationModel" width="220" />
              <el-table-column label="单位" prop="unit" width="100" />
              <el-table-column label="数量" prop="quantity" width="120" />
              <el-table-column label="税率(%)" prop="taxRate" width="120" />
              <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" width="160" />
              <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="180" />
              <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="180" />
<!--              <el-table-column fixed="right" label="操作" width="150" align="center">-->
<!--                <template #default="scope">-->
<!--                  <el-button link type="primary" size="small" @click="openDeliveryForm(props.row, 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="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 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="审核状态" width="140">
          <template #default="scope">
            <el-button link
              <el-tag
                v-if="(scope.row.approveStatus ?? scope.row.approvalStatus) == 0"
                type="warning"
              >待审核</el-tag>
              <el-tag
                v-else-if="(scope.row.approveStatus ?? scope.row.approvalStatus) == 1"
                       type="primary"
                       size="small"
                       @click="openForm('edit', scope.row)">编辑</el-button>
              >审核中</el-tag>
              <el-tag
                v-else-if="(scope.row.approveStatus ?? scope.row.approvalStatus) == 2"
                type="success"
              >审核完成</el-tag>
              <el-tag
                v-else-if="(scope.row.approveStatus ?? scope.row.approvalStatus) == 3"
                type="danger"
              >审核未通过</el-tag>
              <el-tag
                v-else-if="(scope.row.approveStatus ?? scope.row.approvalStatus) == 4"
                type="info"
              >已重新提交</el-tag>
              <el-tag v-else type="info">-</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="销售类型" width="120">
          <template #default="scope">
            <el-tag
              :type="scope.row.salesType === '紧急' ? 'danger' : 'info'"
            >{{ scope.row.salesType || '-' }}</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="150" 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="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="downLoadFile(scope.row)">附件</el-button>
            <el-button link type="primary" size="small" @click="openDeliveryForm(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>
    <el-dialog v-model="dialogFormVisible"
               :title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'"
               width="70%"
    <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'" width="70%"
               @close="closeDia">
      <el-form :model="form"
               label-width="140px"
               label-position="top"
               :rules="rules"
               ref="formRef">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
        <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">
              <el-input v-model="form.salesContractNo" placeholder="自动生成" clearable disabled />
            </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'">
                <el-option v-for="item in userList"
                           :key="item.nickName"
                           :label="item.nickName"
            <el-form-item label="业务员:" prop="salesman">
              <el-select v-model="form.salesman" placeholder="请选择" clearable :disabled="operationType === 'view'">
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
                           :value="item.nickName" />
              </el-select>
            </el-form-item>
@@ -279,25 +142,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 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-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'">
                <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id">
                  {{
                    item.customerName + "——" + item.taxpayerIdentificationNumber
                  }}
@@ -308,155 +160,134 @@
        </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 label="项目名称:" prop="projectName">
              <el-input v-model="form.projectName" placeholder="请输入" clearable :disabled="operationType === 'view'" />
            </el-form-item>
          </el-col>
          <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-row>
        <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-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" placeholder="请选择" clearable @change="changs" disabled>
                                <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 />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="付款方式">
              <el-input v-model="form.paymentMethod"
                        placeholder="请输入"
              <el-input v-model="form.paymentMethod" placeholder="请输入" clearable :disabled="operationType === 'view'" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="销售类型:" prop="salesType">
              <el-select
                v-model="form.salesType"
                placeholder="请选择"
                        clearable
                        :disabled="operationType === 'view'" />
                :disabled="operationType === 'view'"
                style="width: 100%"
              >
                <el-option label="普通" value="普通" />
                <el-option label="紧急" value="紧急" />
              </el-select>
            </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-button>
            <el-button v-if="operationType !== 'view'"
                       plain
          <el-col :span="24">
            <el-form-item v-if="operationType !== 'view'">
              <template #label>
                <span>审批人选择:</span>
                <el-button type="primary" @click="addApproverNode" style="margin-left: 8px;">新增节点</el-button>
              </template>
              <div style="display: flex; align-items: flex-end; flex-wrap: wrap;">
                <div
                  v-for="(node, index) in approverNodes"
                  :key="node.id"
                  style="margin-right: 30px; text-align: center; margin-bottom: 10px;"
                >
                  <div>
                    <span>审批人</span>
                    â†’
                  </div>
                  <el-select
                    v-model="node.userId"
                    placeholder="选择人员"
                    style="width: 140px; margin-bottom: 8px;"
                  >
                    <el-option
                      v-for="user in userList"
                      :key="user.userId"
                      :label="user.nickName"
                      :value="user.userId"
                    />
                  </el-select>
                  <div>
                    <el-button
                       type="danger"
                       @click="deleteProduct">删除</el-button>
                      size="small"
                      @click="removeApproverNode(index)"
                      v-if="approverNodes.length > 1"
                    >删除</el-button>
                  </div>
                </div>
              </div>
            </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-button>
            <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
        <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'" />
          <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 fixed="right"
                           label="操作"
                           min-width="60"
                           align="center"
                           v-if="operationType !== 'view'">
          <el-table-column align="center" type="selection" width="55" v-if="operationType !== 'view'" />
          <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 fixed="right" label="操作" min-width="60" align="center" v-if="operationType !== 'view'">
            <template #default="scope">
              <el-button link
                         type="primary"
                         size="small"
                         @click="openProductForm('edit', scope.row,scope.$index)">编辑</el-button>
              <el-button link type="primary" size="small" @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="remark">
              <el-input v-model="form.remark"
                        placeholder="请输入"
                        clearable
                        type="textarea"
                        :rows="2"
                        :disabled="operationType === 'view'" />
            <el-form-item label="备注·:" prop="remark">
              <el-input v-model="form.remark" placeholder="请输入" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="附件材料:"
                          prop="remark">
              <el-upload v-model:file-list="fileList"
                         :action="upload.url"
                         multiple
                         ref="fileUpload"
                         auto-upload
                         :headers="upload.headers"
                         :before-upload="handleBeforeUpload"
                         :on-error="handleUploadError"
                         :on-success="handleUploadSuccess"
                         :on-remove="handleRemove">
                <el-button type="primary"
                           v-if="operationType !== 'view'">上传</el-button>
                <template #tip
                          v-if="operationType !== 'view'">
            <el-form-item label="附件材料:" prop="remark">
              <el-upload v-model:file-list="fileList" :action="upload.url" multiple ref="fileUpload" auto-upload
                :headers="upload.headers" :before-upload="handleBeforeUpload" :on-error="handleUploadError"
                :on-success="handleUploadSuccess" :on-remove="handleRemove">
                <el-button type="primary" v-if="operationType !== 'view'">上传</el-button>
                <template #tip v-if="operationType !== 'view'">
                  <div class="el-upload__tip">
                    æ–‡ä»¶æ ¼å¼æ”¯æŒ
                    doc,docx,xls,xlsx,ppt,pptx,pdf,txt,xml,jpg,jpeg,png,gif,bmp,rar,zip,7z
@@ -469,140 +300,84 @@
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary"
                     @click="submitForm">确认</el-button>
          <el-button type="primary" @click="submitForm">确认</el-button>
          <el-button @click="closeDia">取消</el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="productFormVisible"
               :title="productOperationType === 'add' ? '新增产品' : '编辑产品'"
               width="40%"
    <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-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-form-item label="产品大类:" prop="productCategory">
              <!-- <el-select v-model="productForm.productCategory" placeholder="请选择" clearable>
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
              </el-select> -->
              <el-tree-select v-model="productForm.productCategory"
                              placeholder="请选择"
                              clearable
                              check-strictly
                              @change="getModels"
                              :data="productOptions"
                              :render-after-expand="false"
                              style="width: 100%" />
              <el-tree-select v-model="productForm.productCategory" placeholder="请选择" clearable 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">
                <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">
                <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 label="1" value="1" />
                                <el-option label="6" value="6" />
                                <el-option label="13" value="13" />
              </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%"
            <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" />
                                                             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
                        <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%" />
                                                                @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>
@@ -610,41 +385,38 @@
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary"
                     @click="submitProduct">确认</el-button>
          <el-button type="primary" @click="submitProduct">确认</el-button>
          <el-button @click="closeProductDia">取消</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- æ‰“印预览弹窗 -->
    <el-dialog v-model="printPreviewVisible"
        <el-dialog
            v-model="printPreviewVisible"
               title="打印预览"
               width="90%"
               :close-on-click-modal="false"
               class="print-preview-dialog">
            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="company-name">鼎诚瑞实业有限责任公司</div>
                <div class="document-title">零售发货单</div>
              </div>
              <div class="info-section">
                <div class="info-row">
                  <div>
@@ -652,6 +424,7 @@
                    <span class="value">{{ formatDate(item.createTime) }}</span>
                  </div>
                  <div>
                    <span class="label">客户名称:</span>
                    <span class="value">{{ item.customerName || '张爱有' }}</span>
                  </div>
@@ -661,6 +434,7 @@
                  <span class="value">{{ item.salesContractNo }}</span>
                </div>
              </div>
              <div class="table-section">
                <table class="product-table">
                  <thead>
@@ -674,8 +448,7 @@
                    </tr>
                  </thead>
                  <tbody>
                    <tr v-for="product in item.products"
                        :key="product.id">
                                    <tr v-for="product in item.products" :key="product.id">
                      <td>{{ product.productCategory || '' }}</td>
                      <td>{{ product.specificationModel || '' }}</td>
                      <td>{{ product.unit || '' }}</td>
@@ -684,8 +457,7 @@
                      <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>
                                        <td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td>
                    </tr>
                  </tbody>
                  <tfoot>
@@ -700,6 +472,7 @@
                  </tfoot>
                </table>
              </div>
              <div class="footer-section">
                <div class="footer-row">
                  <div class="footer-item">
@@ -732,60 +505,43 @@
      </div>
    </el-dialog>
    <!-- å‘货弹框 -->
    <el-dialog v-model="deliveryFormVisible"
        <el-dialog
            v-model="deliveryFormVisible"
               title="发货信息"
               width="40%"
               @close="closeDeliveryDia">
      <el-form :model="deliveryForm"
               label-width="120px"
               label-position="top"
               :rules="deliveryRules"
               ref="deliveryFormRef">
            @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="shippingDate">
              <el-date-picker style="width: 100%"
                        <el-form-item label="发货日期:" prop="shippingDate">
                            <el-date-picker
                                style="width: 100%"
                              v-model="deliveryForm.shippingDate"
                              value-format="YYYY-MM-DD"
                              format="YYYY-MM-DD"
                              type="date"
                              placeholder="请选择发货日期"
                              clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="发货车牌号:"
                          prop="shippingCarNumber">
              <el-input v-model="deliveryForm.shippingCarNumber"
                        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">
                    <el-col :span="24">
                        <el-form-item label="发货车牌号:" prop="shippingCarNumber">
                            <el-input
                                v-model="deliveryForm.shippingCarNumber"
                                placeholder="请输入发货车牌号"
                                clearable
                            />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary"
                     @click="submitDelivery">确认发货</el-button>
                    <el-button type="primary" @click="submitDelivery">确认发货</el-button>
          <el-button @click="closeDeliveryDia">取消</el-button>
        </div>
      </template>
@@ -812,13 +568,15 @@
    delLedger,
    addOrUpdateSalesLedgerProduct,
    delProduct,
    delLedgerFile,
    getProductInventory,
    judgmentInventory,
  delLedgerFile, getProductInventory,
  } from "@/api/salesManagement/salesLedger.js";
  import { modelList, productTreeList } from "@/api/basicData/product.js";
  import useFormData from "@/hooks/useFormData.js";
  import dayjs from "dayjs";
import {
  getStockInPage
} from "@/api/inventoryManagement/stockIn.js";
  const userStore = useUserStore();
  const { proxy } = getCurrentInstance();
@@ -837,6 +595,8 @@
  });
  const total = ref(0);
  const fileList = ref([]);
const approverNodes = ref([{ id: 1, userId: null }]);
let nextApproverId = 2;
  // ç”¨æˆ·ä¿¡æ¯è¡¨å•弹框数据
  const operationType = ref("");
@@ -863,8 +623,10 @@
      productData: [],
      executionDate: "",
      paymentMethod: "",
    salesType: "普通",
    },
    rules: {
    salesType: [{ required: true, message: "请选择销售类型", trigger: "change" }],
      salesman: [{ required: true, message: "请选择", trigger: "change" }],
      customerContractNo: [
        { required: true, message: "请输入", trigger: "blur" },
@@ -878,6 +640,12 @@
  });
  const { form, rules } = toRefs(data);
  const { form: searchForm } = useFormData(data.searchForm);
const addApproverNode = () => {
  approverNodes.value.push({ id: nextApproverId++, userId: null });
};
const removeApproverNode = (index) => {
  approverNodes.value.splice(index, 1);
};
  // äº§å“è¡¨å•弹框数据
  const productFormVisible = ref(false);
  const productOperationType = ref("");
@@ -930,7 +698,7 @@
  // å‘货相关
  const deliveryFormVisible = ref(false);
  const currentDeliveryRow = ref(null);
const currentDeliveryContext = ref(null);
  const deliveryFormData = reactive({
    deliveryForm: {
      shippingDate: "",
@@ -938,22 +706,16 @@
    },
    deliveryRules: {
      shippingDate: [
        { required: true, message: "请选择发货日期", trigger: "change" },
      { required: true, message: "请选择发货日期", trigger: "change" }
      ],
      shippingCarNumber: [
        { required: true, message: "请输入发货车牌号", trigger: "blur" },
      ],
      approverId: [
        {
          required: true,
          message: "",
        },
      { required: true, message: "请输入发货车牌号", trigger: "blur" }
      ],
    },
  });
  const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
  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");
@@ -971,21 +733,19 @@
    expandedRowKeys.value = [];
    getList();
  };
  const paginationChange = obj => {
const paginationChange = (obj) => {
    page.current = obj.page;
    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 })
      .then(res => {
    .then((res) => {
        tableLoading.value = false;
        tableData.value = res.records;
        tableData.value.map(item => {
      tableData.value.map((item) => {
          item.children = [];
        });
        total.value = res.total;
@@ -996,7 +756,7 @@
  };
  // èŽ·å–äº§å“å¤§ç±»tree数据
  const getProductOptions = () => {
    productTreeList().then(res => {
  productTreeList().then((res) => {
      productOptions.value = convertIdToValue(res);
    });
  };
@@ -1004,15 +764,15 @@
    return parseFloat(cellValue).toFixed(2);
  };
  // èŽ·å–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 getProductModel = (value) => {
    console.log("value", value);
    const index = modelOptions.value.findIndex(item => item.id === 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;
@@ -1036,7 +796,7 @@
    return null; // æ²¡æœ‰æ‰¾åˆ°èŠ‚ç‚¹ï¼Œè¿”å›žnull
  };
  function convertIdToValue(data) {
    return data.map(item => {
  return data.map((item) => {
      const { id, children, ...rest } = item;
      const newItem = {
        ...rest,
@@ -1050,44 +810,36 @@
    });
  }
  // è¡¨æ ¼é€‰æ‹©æ•°æ®
  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([]);
  // å±•开行(始终只展开一行)
  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);
      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];
        expandedRowKeys.value.push(row.id);
      });
    } catch (error) {
      console.log(error);
    }
  } else {
    expandedRowKeys.value = [];
  }
  };
  // ä¸»è¡¨åˆè®¡æ–¹æ³•
  const summarizeMainTable = param => {
const summarizeMainTable = (param) => {
    return proxy.summarizeTable(param, [
      "contractAmount",
      "taxInclusiveTotalPrice",
@@ -1095,7 +847,7 @@
    ]);
  };
  // å­è¡¨åˆè®¡æ–¹æ³•
  const summarizeChildrenTable = param => {
const summarizeChildrenTable = (param) => {
    return proxy.summarizeTable(param, [
      "taxInclusiveUnitPrice",
      "taxInclusiveTotalPrice",
@@ -1107,17 +859,35 @@
    operationType.value = type;
    form.value = {};
    productData.value = [];
    customerList().then(res => {
  approverNodes.value = [{ id: 1, userId: null }];
  nextApproverId = 2;
  let userLists = await userListNoPage();
  userList.value = userLists.data;
  customerList().then((res) => {
      customerOption.value = res;
    });
    form.value.entryPerson = userStore.id;
    if (type !== "add") {
      currentId.value = row.id;
      getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
    getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
        form.value = { ...res };
        form.value.entryPerson = Number(res.entryPerson);
      if (!form.value.salesType) {
        form.value.salesType = "普通";
      }
        productData.value = form.value.productData;
        fileList.value = form.value.salesLedgerFiles;
      const approveUserIds = form.value.approveUserIds || form.value.approverIds;
      if (approveUserIds) {
        const ids = String(approveUserIds)
          .split(",")
          .map((id) => Number(id.trim()))
          .filter((id) => !Number.isNaN(id));
        if (ids.length > 0) {
          approverNodes.value = ids.map((id, idx) => ({ id: idx + 1, userId: id }));
          nextApproverId = ids.length + 1;
        }
      }
      });
    }
    // let userAll = await userStore.getInfo()
@@ -1127,6 +897,9 @@
    //   }
    // });
    form.value.entryDate = getCurrentDate(); // è®¾ç½®é»˜è®¤å½•入日期为当前日期
  if (type === "add") {
    form.value.salesType = "普通";
  }
    dialogFormVisible.value = true;
  };
  function changs(val) {
@@ -1163,16 +936,24 @@
    if (operationType.value === "edit") {
      let ids = [];
      ids.push(file.id);
      delLedgerFile(ids).then(res => {
    delLedgerFile(ids).then((res) => {
        proxy.$modal.msgSuccess("删除成功");
      });
    }
  }
  // æäº¤è¡¨å•
  const submitForm = () => {
    proxy.$refs["formRef"].validate(valid => {
  proxy.$refs["formRef"].validate((valid) => {
      if (valid) {
        console.log("productData.value--", productData.value);
      if (operationType.value !== "view") {
        const hasEmptyApprover = approverNodes.value.some((node) => !node.userId);
        if (hasEmptyApprover) {
          proxy.$modal.msgWarning("请为所有审批节点选择审批人");
          return;
        }
        form.value.approveUserIds = approverNodes.value.map((node) => node.userId).join(",");
      }
            console.log('productData.value--', productData.value)
        if (productData.value !== null && productData.value.length > 0) {
          form.value.productData = proxy.HaveJson(productData.value);
        } else {
@@ -1181,11 +962,11 @@
        }
        let tempFileIds = [];
        if (fileList.value !== null && fileList.value.length > 0) {
          tempFileIds = fileList.value.map(item => item.tempId);
        tempFileIds = fileList.value.map((item) => item.tempId);
        }
        form.value.tempFileIds = tempFileIds;
        form.value.type = 1;
        addOrUpdateSalesLedger(form.value).then(res => {
      addOrUpdateSalesLedger(form.value).then((res) => {
          proxy.$modal.msgSuccess("提交成功");
          closeDia();
          getList();
@@ -1214,7 +995,7 @@
  };
  // æäº¤äº§å“è¡¨å•
  const submitProduct = () => {
    proxy.$refs["productFormRef"].validate(valid => {
  proxy.$refs["productFormRef"].validate((valid) => {
      if (valid) {
        if (operationType.value === "edit") {
          submitProductEdit();
@@ -1222,7 +1003,7 @@
          if (productOperationType.value === "add") {
            productData.value.push({ ...productForm.value });
          } else {
            productData.value[productIndex.value] = { ...productForm.value };
          productData.value[productIndex.value] = { ...productForm.value }
          }
          closeProductDia();
        }
@@ -1231,11 +1012,11 @@
  };
  const submitProductEdit = () => {
    productForm.value.salesLedgerId = currentId.value;
    productForm.value.type = 1;
    addOrUpdateSalesLedgerProduct(productForm.value).then(res => {
  productForm.value.type = 1
  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;
      });
    });
@@ -1247,9 +1028,9 @@
      return;
    }
    if (operationType.value === "add") {
      productSelectedRows.value.forEach(selectedRow => {
    productSelectedRows.value.forEach((selectedRow) => {
        const index = productData.value.findIndex(
          product => product.id === selectedRow.id
        (product) => product.id === selectedRow.id
        );
        if (index !== -1) {
          productData.value.splice(index, 1);
@@ -1258,7 +1039,7 @@
    } 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: "确认",
@@ -1266,11 +1047,11 @@
        type: "warning",
      })
        .then(() => {
          delProduct(ids).then(res => {
        delProduct(ids).then((res) => {
            proxy.$modal.msgSuccess("删除成功");
            closeProductDia();
            getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then(
              res => {
            (res) => {
                productData.value = res.productData;
              }
            );
@@ -1304,7 +1085,7 @@
  const handleDelete = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
      ids = selectedRows.value.map(item => item.id);
    ids = selectedRows.value.map((item) => item.id);
    } else {
      proxy.$modal.msgWarning("请选择数据");
      return;
@@ -1315,7 +1096,7 @@
      type: "warning",
    })
      .then(() => {
        delLedger(ids).then(res => {
      delLedger(ids).then((res) => {
          proxy.$modal.msgSuccess("删除成功");
          getList();
        });
@@ -1342,15 +1123,12 @@
      for (const row of selectedRows.value) {
        try {
          // è°ƒç”¨productList接口查询产品数据
          const productRes = await productList({
            salesLedgerId: row.id,
            type: 1,
          });
                const productRes = await productList({ salesLedgerId: row.id, type: 1 });
          // å°†äº§å“æ•°æ®æ•´åˆåˆ°é”€å”®å°è´¦è®°å½•中
          const rowWithProducts = {
            ...row,
            products: productRes.data || [],
                    products: productRes.data || []
          };
          printDataWithProducts.push(rowWithProducts);
@@ -1359,16 +1137,17 @@
          // å³ä½¿æŸä¸ªè®°å½•的产品数据获取失败,也要包含该记录
          printDataWithProducts.push({
            ...row,
            products: [],
                    products: []
          });
        }
      }
      printData.value = printDataWithProducts;
      console.log("打印数据(包含产品):", printData.value);
        console.log('打印数据(包含产品):', printData.value);
      printPreviewVisible.value = true;
    } catch (error) {
      console.error("获取产品数据失败:", error);
        console.error('获取产品数据失败:', error);
      proxy.$modal.msgError("获取产品数据失败,请重试");
    } finally {
      proxy.$modal.closeLoading();
@@ -1376,11 +1155,11 @@
  };
  // æ‰§è¡Œæ‰“印
  const executePrint = () => {
    console.log("开始执行打印,数据条数:", printData.value.length);
    console.log("打印数据:", printData.value);
    console.log('开始执行打印,数据条数:', printData.value.length);
    console.log('打印数据:', printData.value);
    // åˆ›å»ºä¸€ä¸ªæ–°çš„æ‰“印窗口
    const printWindow = window.open("", "_blank", "width=800,height=600");
    const printWindow = window.open('', '_blank', 'width=800,height=600');
    // æž„建打印内容
    let printContent = `
@@ -1532,22 +1311,16 @@
                                    <div class="info-row">
                                      <div>
                                        <span class="label">发货日期:</span>
                                        <span class="value">${formatDate(
                                          item.createTime
                                        )}</span>
                <span class="value">${formatDate(item.createTime)}</span>
                                      </div>
                                      <div>
                                        <span class="label">客户名称:</span>
                                        <span class="value">${
                                          item.customerName || "张爱有"
                                        }</span>
                <span class="value">${item.customerName || '张爱有'}</span>
                                      </div>
                                    </div>
                                    <div class="info-row">
                                      <span class="label">单号:</span>
                                      <span class="value">${
                                        item.salesContractNo || ""
                                      }</span>
              <span class="value">${item.salesContractNo || ''}</span>
                                    </div>
                                  </div>
@@ -1564,34 +1337,18 @@
                                        </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>
                                              <td>${product.unit || ""}</td>
                                              <td>${
                                                product.taxInclusiveUnitPrice ||
                                                "0"
                                              }</td>
                                              <td>${product.quantity || "0"}</td>
                                              <td>${
                                                product.taxInclusiveTotalPrice ||
                                                "0"
                                              }</td>
                      <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>'
                  `).join('') :
                  '<tr><td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td></tr>'
                                        }
                                      </tbody>
                                      <tfoot>
@@ -1600,12 +1357,8 @@
                                          <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>
                  <td class="total-value">${getTotalQuantityForPrint(item.products)}</td>
                  <td class="total-value">${getTotalAmountForPrint(item.products)}</td>
                                        </tr>
                                      </tfoot>
                                    </table>
@@ -1629,15 +1382,11 @@
                                    <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>
                                        <span class="value">${formatDateTime(
                                          new Date()
                                        )}</span>
                <span class="value">${formatDateTime(new Date())}</span>
                                      </div>
                                    </div>
                                  </div>
@@ -1665,7 +1414,7 @@
    };
  };
  // æ ¼å¼åŒ–日期
  const formatDate = dateString => {
const formatDate = (dateString) => {
    if (!dateString) return getCurrentDate();
    const date = new Date(dateString);
    const year = date.getFullYear();
@@ -1674,7 +1423,7 @@
    return `${year}/${month}/${day}`;
  };
  // æ ¼å¼åŒ–日期时间
  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");
@@ -1693,8 +1442,8 @@
  }
  // è®¡ç®—产品总数量
  const getTotalQuantity = products => {
    if (!products || products.length === 0) return "0";
const getTotalQuantity = (products) => {
  if (!products || products.length === 0) return '0';
    const total = products.reduce((sum, product) => {
      return sum + (parseFloat(product.quantity) || 0);
    }, 0);
@@ -1702,8 +1451,8 @@
  };
  // è®¡ç®—产品总金额
  const getTotalAmount = products => {
    if (!products || products.length === 0) return "0";
const getTotalAmount = (products) => {
  if (!products || products.length === 0) return '0';
    const total = products.reduce((sum, product) => {
      return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
    }, 0);
@@ -1711,16 +1460,16 @@
  };
  // ç”¨äºŽæ‰“印的计算函数
  const getTotalQuantityForPrint = products => {
    if (!products || products.length === 0) return "0";
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);
  };
  const getTotalAmountForPrint = products => {
    if (!products || products.length === 0) return "0";
const getTotalAmountForPrint = (products) => {
  if (!products || products.length === 0) return '0';
    const total = products.reduce((sum, product) => {
      return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
    }, 0);
@@ -1787,9 +1536,7 @@
    }
    if (isCalculating.value) return;
    const exclusiveTotalPrice = parseFloat(
      productForm.value.taxExclusiveTotalPrice
    );
  const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice);
    const quantity = parseFloat(productForm.value.quantity);
    const taxRate = parseFloat(productForm.value.taxRate);
@@ -1805,22 +1552,19 @@
    productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
    // è®¡ç®—含税单价 = å«ç¨Žæ€»ä»· / æ•°é‡
    productForm.value.taxInclusiveUnitPrice = (
      inclusiveTotalPrice / quantity
    ).toFixed(2);
  productForm.value.taxInclusiveUnitPrice = (inclusiveTotalPrice / quantity).toFixed(2);
    isCalculating.value = false;
  };
  // æ ¹æ®æ•°é‡å˜åŒ–计算总价
  const calculateFromQuantity = () => {
    // è¿™é‡Œ
    if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
    }
    if (isCalculating.value) return;
    newfunction();
    const quantity = parseFloat(productForm.value.quantity);
    const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
@@ -1844,21 +1588,7 @@
    isCalculating.value = false;
  };
  const newfunction = () => {
    // productForm.value.productModelId;
    // productForm.quantity
    judgmentInventory({
      productModelId: productForm.value.productModelId,
      quantity: productForm.value.quantity,
    }).then(res => {
      console.log("res", res);
      // if (res.code === 200) {
      //   proxy.$modal.msgSuccess("库存充足");
      // } else {
      //   proxy.$modal.msgError(res.msg);
      // }
    });
  };
  // æ ¹æ®å«ç¨Žå•价变化计算总价
  const calculateFromUnitPrice = () => {
    if (!productForm.value.taxRate) {
@@ -1899,9 +1629,7 @@
    }
    if (isCalculating.value) return;
    const inclusiveTotalPrice = parseFloat(
      productForm.value.taxInclusiveTotalPrice
    );
  const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
    const taxRate = parseFloat(productForm.value.taxRate);
    if (!inclusiveTotalPrice || !taxRate) {
@@ -1912,7 +1640,10 @@
    // è®¡ç®—不含税总价
    productForm.value.taxExclusiveTotalPrice =
      proxy.calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate);
    proxy.calculateTaxExclusiveTotalPrice(
      inclusiveTotalPrice,
      taxRate
    );
    isCalculating.value = false;
  };
@@ -1921,39 +1652,40 @@
   *
   * @param row ä¸‹è½½æ–‡ä»¶çš„相关信息对象
   */
  const fileListRef = ref(null);
  const downLoadFile = row => {
    getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
      fileListRef.value.open(res.salesLedgerFiles);
const fileListRef = ref(null)
const downLoadFile = (row) => {
  getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
    fileListRef.value.open(res.salesLedgerFiles)
    });
  };
}
  // æ‰“开发货弹框
  const openDeliveryForm = row => {
const openDeliveryForm = (row) => {
  getProductInventory({ salesLedgerId: row.id, type:1 }).then((res) => {
    currentDeliveryRow.value = row;
    deliveryForm.value = {
      shippingDate: "", // ç§»é™¤é»˜è®¤å€¼è®¾ç½®
      shippingDate: getCurrentDate(),
      shippingCarNumber: "",
    };
    deliveryFormVisible.value = true;
  }).catch(err => {
    ElMessage.error(err.msg);
  });
  };
  // æäº¤å‘货表单
  const submitDelivery = () => {
    proxy.$refs["deliveryFormRef"].validate(valid => {
  proxy.$refs["deliveryFormRef"].validate((valid) => {
      if (valid) {
        addShippingInfo({
          approverId: deliveryForm.value.approverId,
          salesLedgerId: currentDeliveryRow.value.salesLedgerId,
          salesLedgerProductId: currentDeliveryRow.value.id,
        salesLedgerId: currentDeliveryContext.value.parentRow.id,
        salesLedgerProductId: currentDeliveryContext.value.productRow.id,
          shippingDate: deliveryForm.value.shippingDate,
          shippingCarNumber: deliveryForm.value.shippingCarNumber,
        })
          .then(() => {
            proxy.$modal.msgSuccess("发货成功");
            closeDeliveryDia();
            getList();
            expandedRowKeys.value = [];
          })
          .catch(() => {
            proxy.$modal.msgError("发货失败,请重试");
@@ -1966,7 +1698,7 @@
  const closeDeliveryDia = () => {
    proxy.resetForm("deliveryFormRef");
    deliveryFormVisible.value = false;
    currentDeliveryRow.value = null;
  currentDeliveryContext.value = null;
  };
  onMounted(() => {
@@ -2083,8 +1815,7 @@
      border-collapse: collapse;
      border: 1px solid #000;
      th,
      td {
        th, td {
        border: 1px solid #000;
        padding: 6px;
        text-align: center;