ZN
4 天以前 0453b4d1e92d7a4779ad70857891b17ced6abe2e
src/views/procurementManagement/procurementLedger/index.vue
@@ -2,26 +2,47 @@
  <div class="app-container">
    <div class="search_form">
      <div>
        <span class="search_title">采购合同号:</span>
        <el-input
          v-model="searchForm.purchaseContractNumber"
          style="width: 240px"
          placeholder="请输入"
          @change="handleQuery"
          clearable
          prefix-icon="Search"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
          >搜索</el-button
        >
        <el-form :model="searchForm" :inline="true">
          <el-form-item label="供应商名称:">
            <el-input v-model="searchForm.supplierName" placeholder="请输入" clearable prefix-icon="Search"
                      @change="handleQuery" />
          </el-form-item>
          <el-form-item label="采购合同号:">
            <el-input
                v-model="searchForm.purchaseContractNumber"
                style="width: 240px"
                placeholder="请输入"
                @change="handleQuery"
                clearable
                :prefix-icon="Search"
            />
          </el-form-item>
          <el-form-item label="销售合同号:">
            <el-input v-model="searchForm.salesContractNo" placeholder="请输入" clearable prefix-icon="Search"
                      @change="handleQuery" />
          </el-form-item>
          <el-form-item label="项目名称:">
            <el-input v-model="searchForm.projectName" placeholder="请输入" clearable prefix-icon="Search"
                      @change="handleQuery" />
          </el-form-item>
          <el-form-item label="录入日期:">
            <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
                            placeholder="请选择" clearable @change="changeDaterange" />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="handleQuery"> 搜索 </el-button>
          </el-form-item>
        </el-form>
      </div>
      <div>
    </div>
    <div class="table_list">
      <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;">
        <el-button type="primary" @click="openForm('add')">新增台账</el-button>
        <el-button type="success" @click="openScanAddDialog">扫码新增</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
      </div>
    </div>
    <div class="table_list">
      <el-table
        :data="tableData"
        border
@@ -76,43 +97,56 @@
        <el-table-column
          label="采购合同号"
          prop="purchaseContractNumber"
          width="200"
          show-overflow-tooltip
        />
        <el-table-column
          label="销售合同号"
          prop="salesContractNo"
          width="200"
          show-overflow-tooltip
        />
        <el-table-column
          label="供应商名称"
          width="240"
          prop="supplierName"
          show-overflow-tooltip
        />
        <el-table-column
          label="项目名称"
          prop="projectName"
          width="420"
          show-overflow-tooltip
        />
        <el-table-column
          label="付款方式"
          width="100"
          prop="paymentMethod"
          show-overflow-tooltip
        />
        <el-table-column
          label="合同金额(元)"
          prop="contractAmount"
           width="200"
          show-overflow-tooltip
          :formatter="formattedNumber"
        />
        <el-table-column
          label="录入人"
          prop="recorderName"
           width="100"
          show-overflow-tooltip
        />
        <el-table-column
          label="录入日期"
          prop="entryDate"
           width="100"
          show-overflow-tooltip
        />
        <el-table-column
          fixed="right"
          label="操作"
          min-width="60"
          min-width="150"
          align="center"
        >
          <template #default="scope">
@@ -123,6 +157,14 @@
              @click="openForm('edit', scope.row)"
              >编辑</el-button
            >
            <el-button
              link
              type="success"
              size="small"
              @click="showQRCode(scope.row)"
              >生成二维码</el-button
            >
          </template>
        </el-table-column>
      </el-table>
@@ -183,6 +225,7 @@
                v-model="form.supplierId"
                placeholder="请选择"
                clearable
                @change="handleSupplierChange"
              >
                <el-option
                  v-for="item in supplierList"
@@ -203,6 +246,30 @@
            </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="请输入"
                        clearable
                     />
                  </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
                     />
                  </el-form-item>
               </el-col>
            </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="录入人:" prop="recorderId">
@@ -224,7 +291,6 @@
          <el-col :span="12">
            <el-form-item label="录入日期:" prop="entryDate">
              <el-date-picker
                disabled
                style="width: 100%"
                v-model="form.entryDate"
                value-format="YYYY-MM-DD"
@@ -264,7 +330,8 @@
          <el-table-column label="规格型号" prop="specificationModel" />
          <el-table-column label="单位" prop="unit" width="70" />
          <el-table-column label="数量" prop="quantity" width="70" />
          <el-table-column label="税率(%)" prop="taxRate" width="70" />
               <el-table-column label="库存预警数量" prop="warnNum" width="120" show-overflow-tooltip />
          <el-table-column label="税率(%)" prop="taxRate" width="80" />
          <el-table-column
            label="含税单价(元)"
            prop="taxInclusiveUnitPrice"
@@ -405,14 +472,23 @@
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数量:" prop="quantity">
              <el-input
                v-model="productForm.quantity"
                placeholder="请输入"
                clearable
                @change="mathNum"
              />
               <el-col :span="12">
                  <el-form-item label="税率(%):" prop="taxRate">
                     <el-select
                        v-model="productForm.taxRate"
                        placeholder="请选择"
                        clearable
                        @change="mathNum"
                     >
                        <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-col :span="24">
            <el-form-item label=" ">
              <el-button type="warning" :disabled="!(productForm.productId && productForm.productModelId && productForm.taxRate)" @click="showPriceReference" icon="Search">查看历史采购价格参考</el-button>
            </el-form-item>
          </el-col>
        </el-row>
@@ -429,20 +505,19 @@
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="税率(%):" prop="taxRate">
              <el-select
                v-model="productForm.taxRate"
                placeholder="请选择"
                clearable
                @change="mathNum"
              >
                <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-col :span="12">
                  <el-form-item label="数量:" prop="quantity">
                     <el-input-number
                        :step="0.1"
                        clearable
                        :precision="2"
                        style="width: 100%"
                        v-model="productForm.quantity"
                        placeholder="请输入"
                        @change="mathNum"
                     />
                  </el-form-item>
               </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
@@ -453,7 +528,7 @@
                :step="0.1"
                clearable
                style="width: 100%"
                disabled
                @change="reverseMathNum('taxInclusiveTotalPrice')"
              />
            </el-form-item>
          </el-col>
@@ -462,7 +537,10 @@
              label="不含税总价(元):"
              prop="taxExclusiveTotalPrice"
            >
              <el-input v-model="productForm.taxExclusiveTotalPrice" disabled />
              <el-input
                v-model="productForm.taxExclusiveTotalPrice"
                @change="reverseMathNum('taxExclusiveTotalPrice')"
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -479,6 +557,17 @@
              </el-select>
            </el-form-item>
          </el-col>
               <el-col :span="12">
                  <el-form-item label="库存预警数量:" prop="warnNum">
                     <el-input-number
                        v-model="productForm.warnNum"
                        :precision="2"
                        :step="0.1"
                        clearable
                        style="width: 100%"
                     />
                  </el-form-item>
               </el-col>
        </el-row>
      </el-form>
      <template #footer>
@@ -488,14 +577,306 @@
        </div>
      </template>
    </el-dialog>
    <!-- 二维码显示对话框 -->
    <el-dialog
      v-model="qrCodeDialogVisible"
      title="采购合同号二维码"
      width="400px"
      center
    >
      <div style="text-align: center;">
        <img :src="qrCodeUrl" alt="二维码" style="width:200px;height:200px;" />
        <div style="margin: 20px;">
          <el-button type="primary" @click="downloadQRCode">下载二维码图片</el-button>
        </div>
      </div>
    </el-dialog>
    <!-- 扫码新增对话框 -->
    <el-dialog
      v-model="scanAddDialogVisible"
      title="扫码新增采购台账"
      width="70%"
      @close="closeScanAddDialog"
    >
      <el-form
        :model="scanAddForm"
        label-width="140px"
        label-position="top"
        :rules="scanAddRules"
        ref="scanAddFormRef"
      >
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="扫码内容:">
              <el-input
                v-model="scanAddForm.scanContent"
                type="textarea"
                :rows="3"
                placeholder="请扫描二维码或手动输入采购合同信息"
                @input="parseScanContent"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="采购合同号:" prop="purchaseContractNumber">
              <el-input
                v-model="scanAddForm.purchaseContractNumber"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="供应商名称:" prop="supplierName">
              <el-input
                v-model="scanAddForm.supplierName"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="项目名称:" prop="projectName">
              <el-input
                v-model="scanAddForm.projectName"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="合同金额(元):" prop="contractAmount">
              <el-input-number
                v-model="scanAddForm.contractAmount"
                :precision="2"
                :step="0.1"
                clearable
                style="width: 100%"
                placeholder="请输入"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="付款方式:">
              <el-input
                v-model="scanAddForm.paymentMethod"
                placeholder="请输入"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="录入人:">
              <el-input v-model="scanAddForm.recorderName" disabled />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="备注:">
              <el-input
                v-model="scanAddForm.remark"
                type="textarea"
                :rows="2"
                placeholder="请输入备注信息"
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitScanAdd">确认新增</el-button>
          <el-button @click="closeScanAddDialog">取消</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- 历史采购价格参考弹窗 -->
    <el-dialog
      v-model="priceReferenceVisible"
      :title="`历史采购价格参考 ${productForm.supplierName}-${productForm.productName}-${productForm.productModel}`"
      width="1000px"
      append-to-body
    >
      <el-table
        :data="priceReferenceData"
        border
        v-loading="priceReferenceLoading"
        :default-sort="{ prop: 'updateTime', order: 'descending' }"
      >
        <!-- <el-table-column label="商品信息" min-width="200">
          <template #default="{ row }">
            <div class="product-info">
              <div class="product-name">{{ row.productName }}</div>
              <div class="product-spec">{{ row.specification }}</div>
              <div class="product-code">编码: {{ row.productCode }}</div>
            </div>
          </template>
        </el-table-column> -->
        <!-- <el-table-column label="供应商" prop="supplierName" width="200" /> -->
        <el-table-column label="基础价格(不含税)" width="150" align="right">
          <template #default="{ row }">
            <span class="price-text">¥{{ row.basePrice }}</span>
          </template>
        </el-table-column>
        <el-table-column label="实际价格(不含税)" prop="actuallyPrice" width="150" align="right"/>
        <el-table-column label="折扣信息" width="120" align="center">
          <template #default="{ row }">
            <div v-if="row.discountType">
              <el-tag :type="getDiscountTagType(row.discountType)" size="small">
                {{ getDiscountText(row.discountType) }}
              </el-tag>
              <div class="discount-value">{{ row.discountValue }}{{ row.discountType === 'percentage' ? '%' : '元' }}</div>
            </div>
            <span v-else class="no-discount">无折扣</span>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="100" align="center">
          <template #default="{ row }">
            <el-tag :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag>
            <!-- <div v-if="isPriceWarning(row)" class="warning-indicator">
              <el-icon color="#F56C6C"><Warning /></el-icon>
            </div> -->
          </template>
        </el-table-column>
        <el-table-column label="生效时间" prop="effectiveTime" width="100" align="center" />
        <el-table-column label="更新时间" prop="updateTime" width="160" sortable align="center" />
        <el-table-column label="备注" width="200" prop="remark" align="center" show-overflow-tooltip />
        <el-table-column label="操作" width="100" align="center" fixed="right">
          <template #default="{ row }">
            <el-button type="success" link @click="selectPriceReference(row)">
              <el-icon><Check /></el-icon>
              引用
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <div class="pagination-container" style="margin-top: 20px; display: flex; justify-content: flex-end;">
        <el-pagination
          v-model:current-page="priceReferencePagination.current"
          v-model:page-size="priceReferencePagination.size"
          :page-sizes="[10, 20, 50]"
          :total="priceReferenceTotal"
          layout="total, sizes, prev, pager, next"
          @size-change="handlePriceReferenceSizeChange"
          @current-change="handlePriceReferenceCurrentChange"
        />
      </div>
      <template #footer>
        <el-button @click="priceReferenceVisible = false">关闭</el-button>
      </template>
    </el-dialog>
    <!-- 扫码登记对话框 -->
    <el-dialog
      v-model="scanDialogVisible"
      title="扫码登记"
      width="60%"
      @close="closeScanDialog"
    >
      <el-form
        :model="scanForm"
        label-width="120px"
        label-position="left"
        :rules="scanRules"
        ref="scanFormRef"
      >
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="采购合同号:">
              <el-input v-model="scanForm.purchaseContractNumber" disabled />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="供应商名称:">
              <el-input v-model="scanForm.supplierName" disabled />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="项目名称:">
              <el-input v-model="scanForm.projectName" disabled />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="扫码时间:">
              <el-input v-model="scanForm.scanTime" disabled />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="扫码人:">
              <el-input v-model="scanForm.scannerName" disabled />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="扫码状态:">
              <el-tag :type="scanForm.scanStatus === '已扫码' ? 'success' : 'warning'">
                {{ scanForm.scanStatus }}
              </el-tag>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="扫码备注:">
              <el-input
                v-model="scanForm.scanRemark"
                type="textarea"
                :rows="3"
                placeholder="请输入扫码备注信息"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="扫码记录:">
              <el-table :data="scanRecords" border style="width: 100%">
                <el-table-column label="序号" type="index" width="60" align="center" />
                <el-table-column label="扫码时间" prop="scanTime" width="180" />
                <el-table-column label="扫码人" prop="scannerName" width="120" />
                <el-table-column label="扫码状态" prop="scanStatus" width="100">
                  <template #default="scope">
                    <el-tag :type="scope.row.scanStatus === '已扫码' ? 'success' : 'warning'">
                      {{ scope.row.scanStatus }}
                    </el-tag>
                  </template>
                </el-table-column>
                <el-table-column label="备注" prop="scanRemark" />
              </el-table>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitScan">确认扫码</el-button>
          <el-button @click="closeScanDialog">取消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { getToken } from "@/utils/auth";
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref, onMounted } from "vue";
import { Search } from "@element-plus/icons-vue";
import { ref, onMounted, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
import { Search, Check } from "@element-plus/icons-vue";
import { ElMessageBox } from "element-plus";
import { userListNoPage } from "@/api/system/user.js";
import {
@@ -513,7 +894,10 @@
  productList,
  getPurchaseById,
  getOptions,
  createPurchaseNo,
} from "@/api/procurementManagement/procurementLedger.js";
import useFormData from "@/hooks/useFormData.js";
import QRCode from "qrcode";
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const productData = ref([]);
@@ -533,15 +917,27 @@
const fileList = ref([]);
import useUserStore from "@/store/modules/user";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import { listPage as listAdvancedPrice } from "@/api/procurementManagement/advancedPriceManagement.js";
import dayjs from "dayjs";
const userStore = useUserStore();
// 二维码相关变量
const qrCodeDialogVisible = ref(false);
const qrCodeUrl = ref("");
// 用户信息表单弹框数据
const operationType = ref("");
const dialogFormVisible = ref(false);
const data = reactive({
  searchForm: {
    purchaseContractNumber: "",
    supplierName: "", // 供应商名称
    purchaseContractNumber: "", // 采购合同编号
    salesContractNo: "", // 销售合同编号
    projectName: "", // 项目名称
    entryDate: null, // 录入日期
    entryDateStart: undefined,
    entryDateEnd: undefined,
  },
  form: {
    purchaseContractNumber: "",
@@ -552,6 +948,8 @@
    productData: [],
    supplierName: "",
    supplierId: "",
    paymentMethod: "",
      executionDate: "",
  },
  rules: {
    purchaseContractNumber: [
@@ -559,9 +957,13 @@
    ],
    projectName: [{ required: true, message: "请输入", trigger: "blur" }],
    supplierId: [{ required: true, message: "请输入", trigger: "blur" }],
      entryDate: [{ required: true, message: "请选择", trigger: "change" }],
      executionDate: [{ required: true, message: "请选择", trigger: "change" }],
  },
});
const { searchForm, form, rules } = toRefs(data);
const {  form, rules } = toRefs(data);
const { form: searchForm } = useFormData(data.searchForm);
// 产品表单弹框数据
const productFormVisible = ref(false);
const productOperationType = ref("");
@@ -580,6 +982,10 @@
    taxInclusiveTotalPrice: "",
    taxExclusiveTotalPrice: "",
    invoiceType: "",
      warnNum: "",
    supplierName: "",
    productName: "",
    productModel: "",
  },
  productRules: {
    productId: [{ required: true, message: "请选择", trigger: "change" }],
@@ -590,6 +996,7 @@
      { required: true, message: "请输入", trigger: "blur" },
    ],
    taxRate: [{ required: true, message: "请选择", trigger: "change" }],
      warnNum: [{ required: false, message: "请选择", trigger: "change" }],
    taxInclusiveTotalPrice: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
@@ -600,12 +1007,156 @@
  },
});
const { productForm, productRules } = toRefs(productFormData);
// 采购价格管理参考弹窗
const priceReferenceVisible = ref(false);
const priceReferenceLoading = ref(false);
const priceReferenceData = ref([]);
const priceReferenceTotal = ref(0);
const priceReferencePagination = reactive({
  current: 1,
  size: 10
});
const calculateFinalPrice = (row) => {
  let finalPrice = row.basePrice;
  if (row.discountType === "percentage") {
    finalPrice = row.basePrice * (1 - row.discountValue / 100);
  } else if (row.discountType === "fixed") {
    finalPrice = row.basePrice - row.discountValue;
  }
  let man = Math.max(finalPrice, 0);
  return man.toFixed(2);
};
const getDiscountTagType = (discountType) => {
  const typeMap = {
    percentage: "success",
    fixed: "warning",
    tiered: "info",
  };
  return typeMap[discountType] || "info";
};
const getDiscountText = (discountType) => {
  const textMap = {
    percentage: "百分比",
    fixed: "固定金额",
  };
  return textMap[discountType] || "未知";
};
const getStatusType = (status) => {
  const statusMap = {
    active: "success",
    pending: "warning",
    expired: "info",
  };
  return statusMap[status] || "info";
};
const getStatusText = (status) => {
  const statusMap = {
    active: "有效",
    pending: "待生效",
    expired: "已过期",
  };
  return statusMap[status] || "未知";
};
const showPriceReference = () => {
  if (form.value.supplierId) {
    const supplier = supplierList.value.find((item) => item.id === form.value.supplierId);
    if (supplier) {
      productForm.value.supplierName = supplier.supplierName;
    }
  }
  priceReferenceVisible.value = true;
  handlePriceReferenceSearch();
};
const handlePriceReferenceSearch = () => {
  priceReferenceLoading.value = true;
  // 模拟搜索参数:productId 映射为 productName 或 ID,这里根据 advancedPriceManagement 的 API 确定参数
  // 假设高级价格管理的 listPage 接收 productId
  const query = {
    productId: productForm.value.productId,
    supplierId: form.value.supplierId,
    current: priceReferencePagination.current,
    size: priceReferencePagination.size
  };
  listAdvancedPrice(query).then(res => {
    console.log(res);
    priceReferenceData.value = res.data.records;
    priceReferenceTotal.value = res.data.total;
    priceReferenceLoading.value = false;
  }).catch(() => {
    priceReferenceLoading.value = false;
  });
};
const handlePriceReferenceSizeChange = (size) => {
  priceReferencePagination.size = size;
  handlePriceReferenceSearch();
};
const handlePriceReferenceCurrentChange = (page) => {
  priceReferencePagination.current = page;
  handlePriceReferenceSearch();
};
const selectPriceReference = (row) => {
  // 计算历史价格(作为不含税单价):基础价格 - 折扣
  let taxExclusivePrice = row.basePrice;
  if (row.discountType === "percentage") {
    taxExclusivePrice = row.basePrice * (1 - row.discountValue / 100);
  } else if (row.discountType === "fixed") {
    taxExclusivePrice = row.basePrice - row.discountValue;
  }
  taxExclusivePrice = Number(Math.max(taxExclusivePrice, 0));
  // 设置数量为 1
  if (!productForm.value.quantity) {
    productForm.value.quantity = 1;
  }
  // 如果已有税率,则计算含税单价
  if (productForm.value.taxRate) {
    const taxRate = Number(productForm.value.taxRate);
    productForm.value.taxInclusiveUnitPrice = (
      taxExclusivePrice *
      (1 + taxRate / 100)
    ).toFixed(2);
  } else {
    // 如果没有税率,暂时将含税单价设为不含税价格,提示用户选择税率
    productForm.value.taxInclusiveUnitPrice = taxExclusivePrice.toFixed(2);
    proxy.$modal.msgWarning("请选择税率以准确计算含税价格");
  }
  // 自动触发计算逻辑(计算总价等)
  mathNum();
  priceReferenceVisible.value = false;
  proxy.$modal.msgSuccess("已引用历史价格(不含税)");
};
const upload = reactive({
  // 上传的地址
  url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
  // 设置上传的请求头部
  headers: { Authorization: "Bearer " + getToken() },
});
const changeDaterange = (value) => {
  if (value) {
    searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
    searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
  } else {
    searchForm.entryDateStart = undefined;
    searchForm.entryDateEnd = undefined;
  }
  handleQuery();
};
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
@@ -642,14 +1193,15 @@
};
const getList = () => {
  tableLoading.value = true;
  purchaseListPage({ ...searchForm.value, ...page })
  const { entryDate, ...rest } = searchForm;
  purchaseListPage({ ...rest, ...page })
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.records;
      tableData.value = res.data.records;
      tableData.value.map((item) => {
        item.children = [];
      });
      total.value = res.total;
      total.value = res.data.total;
      expandedRowKeys.value = [];
    })
    .catch(() => {
@@ -672,7 +1224,7 @@
      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;
          tableData.value[index].children = res.data;
        }
        expandedRowKeys.value.push(row.id);
      });
@@ -701,6 +1253,11 @@
  form.value = {};
  productData.value = [];
  fileList.value = [];
  if (operationType.value == "add") {
    createPurchaseNo().then((res) => {
      form.value.purchaseContractNumber = res.data;
    });
  }
  userListNoPage().then((res) => {
    userList.value = res.data;
  });
@@ -755,6 +1312,10 @@
// 移除文件
function handleRemove(file) {
  console.log("handleRemove", file.id);
  if (file.size > 1024 * 1024 * 10) {
    // 仅前端清理,不调用删除接口和提示
    return;
  }
  if (operationType.value === "edit") {
    let ids = [];
    ids.push(file.id);
@@ -794,13 +1355,38 @@
};
// 打开产品弹框
const openProductForm = (type, row, index) => {
  if(!form.value.supplierId){
    proxy.$modal.msgWarning("请选择供应商");
    return;
  }
  productOperationType.value = type;
  productOperationIndex.value = index;
  productForm.value = {};
  productForm.value = {
    supplierName: "",
    productName: "",
    productModel: "",
  };
  proxy.resetForm("productFormRef");
  if (type === "edit") {
    productForm.value = { ...row };
    productForm.value = {
      ...row,
      productName: row.productCategory || "",
      productModel: row.specificationModel || ""
    };
    // 编辑时,根据 productId 预加载规格型号列表,确保下拉框显示名称而非 ID
    if (productForm.value.productId) {
      modelList({ id: productForm.value.productId }).then((res) => {
        modelOptions.value = res;
      });
    }
  }
  // 确保供应商名称始终同步
  const supplier = supplierList.value.find((item) => item.id === form.value.supplierId);
  if (supplier) {
    productForm.value.supplierName = supplier.supplierName;
  }
  productFormVisible.value = true;
  getProductOptions();
};
@@ -810,30 +1396,50 @@
  });
};
const getModels = (value) => {
  productForm.value.productCategory = findNodeById(productOptions.value, value);
  modelList({ id: value }).then((res) => {
    modelOptions.value = res;
  });
  if (value) {
    productForm.value.productCategory = findNodeById(productOptions.value, value) || "";
    productForm.value.productName = productForm.value.productCategory;
    productForm.value.productModelId = "";
    modelList({ id: value }).then((res) => {
      modelOptions.value = res;
    });
  } else {
    productForm.value.productCategory = "";
    productForm.value.productName = "";
    modelOptions.value = [];
  }
};
const getProductModel = (value) => {
  const index = modelOptions.value.findIndex((item) => item.id === value);
  if (index !== -1) {
    productForm.value.specificationModel = modelOptions.value[index].model;
    productForm.value.productModel = modelOptions.value[index].model;
    productForm.value.unit = modelOptions.value[index].unit;
  } else {
    productForm.value.specificationModel = null;
    productForm.value.productModel = null;
    productForm.value.unit = null;
  }
};
const handleSupplierChange = (value) => {
  const supplier = supplierList.value.find((item) => item.id === value);
  if (supplier) {
    form.value.supplierName = supplier.supplierName;
    productForm.value.supplierName = supplier.supplierName;
  } else {
    form.value.supplierName = "";
    productForm.value.supplierName = "";
  }
};
const findNodeById = (nodes, productId) => {
  for (let i = 0; i < nodes.length; i++) {
    if (nodes[i].value === productId) {
      return nodes[i].label; // 找到节点,返回该节点
      return nodes[i].label; // 找到节点,返回该节点的label
    }
    if (nodes[i].children && nodes[i].children.length > 0) {
      const foundNode = findNodeById(nodes[i].children, productId);
      if (foundNode) {
        return foundNode.label; // 在子节点中找到,返回该节点
        return foundNode; // 在子节点中找到,直接返回(已经是label字符串)
      }
    }
  }
@@ -948,6 +1554,12 @@
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;
      }
    ids = selectedRows.value.map((item) => item.id);
  } else {
    proxy.$modal.msgWarning("请选择数据");
@@ -977,7 +1589,10 @@
  return `${year}-${month}-${day}`;
}
const mathNum = () => {
  console.log("productForm.value", productForm.value);
   if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
   }
  if (!productForm.value.taxInclusiveUnitPrice) {
    return;
  }
@@ -999,6 +1614,43 @@
      );
  }
};
const reverseMathNum = (field) => {
   if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
   }
  const taxRate = Number(productForm.value.taxRate);
  if (!taxRate) return;
  if (field === 'taxInclusiveTotalPrice') {
    // 已知含税总价和数量,反算含税单价
    if (productForm.value.quantity) {
      productForm.value.taxInclusiveUnitPrice =
        (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2);
    }
    // 已知含税总价和含税单价,反算数量
    else if (productForm.value.taxInclusiveUnitPrice) {
      productForm.value.quantity =
        (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2);
    }
    // 反算不含税总价
    productForm.value.taxExclusiveTotalPrice =
      (Number(productForm.value.taxInclusiveTotalPrice) / (1 + taxRate / 100)).toFixed(2);
  } else if (field === 'taxExclusiveTotalPrice') {
    // 反算含税总价
    productForm.value.taxInclusiveTotalPrice =
      (Number(productForm.value.taxExclusiveTotalPrice) * (1 + taxRate / 100)).toFixed(2);
    // 已知数量,反算含税单价
    if (productForm.value.quantity) {
      productForm.value.taxInclusiveUnitPrice =
        (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2);
    }
    // 已知含税单价,反算数量
    else if (productForm.value.taxInclusiveUnitPrice) {
      productForm.value.quantity =
        (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2);
    }
  }
};
// 销售合同选择改变方法
const salesLedgerChange = async (row) => {
  console.log("row", row);
@@ -1019,6 +1671,194 @@
  }
};
// 显示二维码
const showQRCode = async (row) => {
  try {
    // 构建二维码内容,只包含采购合同号(纯文本)
    const qrContent = row.purchaseContractNumber || '';
    // 检查内容是否为空
    if (!qrContent || qrContent.trim() === '') {
      proxy.$modal.msgWarning("该行没有采购合同号,无法生成二维码");
      return;
    }
    qrCodeUrl.value = await QRCode.toDataURL(qrContent, {
      width: 200,
      margin: 2,
      color: {
        dark: '#000000',
        light: '#FFFFFF'
      }
    });
    qrCodeDialogVisible.value = true;
  } catch (error) {
    console.error('生成二维码失败:', error);
    proxy.$modal.msgError("生成二维码失败:" + error.message);
  }
};
// 下载二维码
const downloadQRCode = () => {
  if (!qrCodeUrl.value) {
    proxy.$modal.msgWarning("二维码未生成");
    return;
  }
  const a = document.createElement('a');
  a.href = qrCodeUrl.value;
  a.download = `采购合同号二维码_${new Date().getTime()}.png`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  proxy.$modal.msgSuccess("下载成功");
};
// 扫码新增对话框相关变量
const scanAddDialogVisible = ref(false);
const scanAddForm = reactive({
  scanContent: "",
  purchaseContractNumber: "",
  supplierName: "",
  projectName: "",
  contractAmount: "",
  paymentMethod: "",
  recorderName: "",
  scanRemark: "",
});
const scanAddRules = {
  purchaseContractNumber: [{ required: true, message: "请输入采购合同号", trigger: "blur" }],
  supplierName: [{ required: true, message: "请输入供应商名称", trigger: "blur" }],
  projectName: [{ required: true, message: "请输入项目名称", trigger: "blur" }],
};
// 扫码登记对话框相关变量
const scanDialogVisible = ref(false);
const scanForm = reactive({
  purchaseContractNumber: "",
  supplierName: "",
  projectName: "",
  scanTime: "",
  scannerName: "",
  scanStatus: "未扫码",
  scanRemark: "",
});
const scanRules = {
  scanRemark: [{ required: true, message: "请输入扫码备注", trigger: "blur" }],
};
const scanRecords = ref([]);
// 打开扫码新增对话框
const openScanAddDialog = () => {
  scanAddForm.scanContent = "";
  scanAddForm.purchaseContractNumber = "";
  scanAddForm.supplierName = "";
  scanAddForm.projectName = "";
  scanAddForm.contractAmount = "";
  scanAddForm.paymentMethod = "";
  scanAddForm.recorderName = userStore.nickName;
  scanAddForm.scanRemark = "";
  scanAddDialogVisible.value = true;
};
// 解析扫码内容(模拟解析二维码数据)
const parseScanContent = (content) => {
  if (!content) return;
  // 模拟解析二维码内容,这里可以根据实际需求调整解析逻辑
  // 假设扫码内容格式为:合同号|供应商|项目|金额|付款方式
  const parts = content.split('|');
  if (parts.length >= 3) {
    scanAddForm.purchaseContractNumber = parts[0] || "";
    scanAddForm.supplierName = parts[1] || "";
    scanAddForm.projectName = parts[2] || "";
    scanAddForm.contractAmount = parts[3] || "";
    scanAddForm.paymentMethod = parts[4] || "";
  }
};
// 关闭扫码新增对话框
const closeScanAddDialog = () => {
  scanAddDialogVisible.value = false;
  proxy.resetForm("scanAddFormRef");
};
// 提交扫码新增
const submitScanAdd = () => {
  proxy.$refs["scanAddFormRef"].validate((valid) => {
    if (valid) {
      // 构建新增数据
      const newData = {
        purchaseContractNumber: scanAddForm.purchaseContractNumber,
        supplierName: scanAddForm.supplierName,
        projectName: scanAddForm.projectName,
        contractAmount: scanAddForm.contractAmount,
        paymentMethod: scanAddForm.paymentMethod,
        recorderName: scanAddForm.recorderName,
        entryDate: getCurrentDate(),
        remark: scanAddForm.scanRemark,
        type: 2
      };
      // 模拟新增成功
      proxy.$modal.msgSuccess("扫码新增成功!");
      closeScanAddDialog();
      // 可以选择是否刷新列表
      // getList();
    }
  });
};
// 打开扫码登记对话框
const openScanDialog = (row) => {
  scanForm.purchaseContractNumber = row.purchaseContractNumber;
  scanForm.supplierName = row.supplierName;
  scanForm.projectName = row.projectName;
  scanForm.scanTime = getCurrentDateTime();
  scanForm.scannerName = userStore.nickName;
  scanForm.scanStatus = "未扫码";
  scanForm.scanRemark = "";
  scanRecords.value = [];
  scanDialogVisible.value = true;
};
// 关闭扫码登记对话框
const closeScanDialog = () => {
  scanDialogVisible.value = false;
  proxy.resetForm("scanFormRef");
};
// 提交扫码登记
const submitScan = () => {
  proxy.$refs["scanFormRef"].validate((valid) => {
    if (valid) {
      // 添加扫码记录
      scanRecords.value.push({
        ...scanForm,
        id: Date.now(), // 模拟ID
        scanTime: getCurrentDateTime(),
      });
      scanForm.scanStatus = "已扫码";
      scanForm.scanRemark = scanForm.scanRemark || "无";
      proxy.$modal.msgSuccess("扫码登记成功!");
      closeScanDialog();
    }
  });
};
// 获取当前日期时间
function getCurrentDateTime() {
  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}`;
}
onMounted(() => {
  getList();
});