gaoluyang
2026-06-29 bcefcad229dc22a8994364afc7827aab8123dd79
src/views/salesManagement/salesLedger/index.vue
@@ -2,6 +2,15 @@
  <div class="app-container">
    <div class="search_form">
      <el-form :model="searchForm" :inline="true">
        <el-form-item label="总合同号:">
          <el-input
            v-model="searchForm.masterContractNo"
            placeholder="请输入"
            clearable
            prefix-icon="Search"
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="客户名称:">
          <el-input
            v-model="searchForm.customerName"
@@ -11,7 +20,7 @@
            @change="handleQuery"
          />
        </el-form-item>
        <el-form-item label="销售合同号:">
        <el-form-item label="订单号:">
          <el-input
            v-model="searchForm.salesContractNo"
            placeholder="请输入"
@@ -56,7 +65,7 @@
            >导入
          </el-button>
          <el-button @click="handleOut">导出</el-button>
          <el-button type="danger" plain @click="handleDelete">删除 </el-button>
          <el-button type="danger" plain @click="handleDelete" v-hasPermi="['salesManagement:salesLedger:remove']">删除 </el-button>
          <el-button type="primary" plain @click="handlePrint">打印 </el-button>
        </div>
      </div>
@@ -183,9 +192,21 @@
        </el-table-column>
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column
          label="销售合同号"
          label="销售总合同号"
          prop="masterContractNo"
          width="150"
          show-overflow-tooltip
        />
        <el-table-column
          label="订单号"
          prop="salesContractNo"
          width="180"
          show-overflow-tooltip
        />
        <el-table-column
          label="采购合同号"
          prop="purchaseMasterContractNo"
          width="150"
          show-overflow-tooltip
        />
        <el-table-column
@@ -248,24 +269,41 @@
          width="200"
          show-overflow-tooltip
        />
        <el-table-column fixed="right" label="操作" width="220" align="center">
        <el-table-column
          label="退货状态"
          prop="returnStatus"
          align="center"
          width="100"
        >
          <template #default="scope">
            <el-tag
              :type="getReturnStatusType(scope.row.returnStatus)"
              size="small"
            >
              {{ scope.row.returnStatus || '无退货' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column fixed="right" label="操作" width="280" align="center">
          <template #default="scope">
                  <el-button
                     link
                type="primary"
                @click="openForm('edit', scope.row)"
                  >编辑
                  </el-button>
            <el-button link type="primary" @click="openForm('view', scope.row)"
              >详情
            </el-button>
            <el-button link type="primary" @click="openFileDialog(scope.row)"
              >附件
            </el-button>
            <el-button
              link
              type="primary"
              @click="openForm('edit', scope.row)"
              :disabled="
                !scope.row.isEdit ||
                scope.row.hasProductionRecord ||
                !canEditLedger(scope.row)
              "
              >编辑
            </el-button>
            <el-button link type="primary" @click="openFileDialog(scope.row)"
              >附件
              v-if="scope.row.masterContractNo"
              @click="openContractFileDialog(scope.row)"
              >总合同附件
            </el-button>
          </template>
        </el-table-column>
@@ -311,7 +349,7 @@
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="销售合同号:" prop="salesContractNo">
            <el-form-item label="订单号:" prop="salesContractNo">
              <div
                style="
                  display: flex;
@@ -366,6 +404,7 @@
                clearable
                :disabled="operationType === 'view'"
                filterable
                @change="handleCustomerChange"
              >
                <el-option
                  v-for="item in customerOption"
@@ -381,6 +420,26 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="总合同号:">
              <el-select
                v-model="form.masterContractNo"
                placeholder="请先选择客户"
                clearable
                filterable
                :disabled="operationType === 'view' || !form.customerId"
              >
                <el-option
                  v-for="item in contractList"
                  :key="item.id"
                  :label="item.masterContractNo"
                  :value="item.masterContractNo"
                />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="项目名称:" prop="projectName">
              <el-input
                v-model="form.projectName"
@@ -390,8 +449,6 @@
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="签订日期:" prop="executionDate">
              <el-date-picker
@@ -406,11 +463,53 @@
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="付款方式">
              <el-input
              <el-select
                v-model="form.paymentMethod"
                placeholder="请输入"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'view'"
                style="width: 100%"
              >
                <el-option label="现金" value="现金" />
                <el-option label="电汇" value="电汇" />
                <el-option label="微信" value="微信" />
                <el-option label="支付宝" value="支付宝" />
                <el-option label="支票" value="支票" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="采购合同号:" prop="purchaseContractNumber">
              <el-select
                v-model="form.purchaseContractNumber"
                placeholder="请选择采购合同号"
                clearable
                filterable
                style="width: 100%"
                :disabled="operationType === 'view'"
              >
                <el-option
                  v-for="item in purchaseContractOptions"
                  :key="item.purchaseContractNumber"
                  :label="item.purchaseContractNumber + ' - ' + item.supplierName"
                  :value="item.purchaseContractNumber"
                />
              </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.deliveryDate"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                type="date"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'view'"
              />
@@ -454,22 +553,6 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="交货日期:" prop="entryDate">
              <el-date-picker
                style="width: 100%"
                v-model="form.deliveryDate"
                value-format="YYYY-MM-DD"
                format="YYYY-MM-DD"
                type="date"
                placeholder="请选择"
                clearable
                :disabled="operationType === 'view'"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-form-item label="产品信息:" prop="entryDate">
            <el-button
@@ -482,8 +565,7 @@
              v-if="operationType !== 'view'"
              plain
              type="danger"
              @click="deleteProduct"
              >删除
              @click="deleteProduct">删除
            </el-button>
          </el-form-item>
        </el-row>
@@ -515,25 +597,26 @@
          <el-table-column
            label="含税单价(元)"
            prop="taxInclusiveUnitPrice"
            :formatter="formattedNumber"
            :formatter="sensitiveAmountFormatter"
          />
          <el-table-column
            label="含税总价(元)"
            prop="taxInclusiveTotalPrice"
            :formatter="formattedNumber"
            :formatter="sensitiveAmountFormatter"
          />
          <el-table-column
            label="不含税总价(元)"
            prop="taxExclusiveTotalPrice"
            :formatter="formattedNumber"
            :formatter="sensitiveAmountFormatter"
          />
          <el-table-column label="是否生产" prop="isProduction" width="150">
          <!-- 是否生产列已隐藏,默认值为 false -->
          <!-- <el-table-column label="是否生产" prop="isProduction" width="150">
            <template #default="scope">
              <el-tag :type="scope.row.isProduction ? 'success' : 'info'">
                {{ scope.row.isProduction ? "是" : "否" }}
              </el-tag>
            </template>
          </el-table-column>
          </el-table-column> -->
          <el-table-column
            fixed="right"
            label="操作"
@@ -823,14 +906,15 @@
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
          <!-- 是否生产字段已隐藏,默认值为 false -->
          <!-- <el-col :span="12">
            <el-form-item label="是否生产:" prop="isProduction">
              <el-radio-group v-model="productForm.isProduction">
                <el-radio label="是" :value="true" />
                <el-radio label="否" :value="false" />
              </el-radio-group>
            </el-form-item>
          </el-col>
          </el-col> -->
        </el-row>
      </el-form>
    </FormDialog>
@@ -877,6 +961,29 @@
      record-type="sales_ledger"
      :record-id="recordId"
    />
    <!-- 总合同附件弹窗 -->
    <el-dialog
      v-model="contractFileDialogVisible"
      title="总合同附件"
      width="700px"
      :close-on-click-modal="false"
    >
      <el-table :data="contractFileList" border v-if="contractFileList.length">
        <el-table-column prop="name" label="文件名称" show-overflow-tooltip />
        <el-table-column prop="byteSize" label="文件大小" width="120">
          <template #default="{ row }">
            {{ formatFileSize(row.byteSize) }}
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150">
          <template #default="{ row }">
            <el-link type="primary" :href="row.previewURL" target="_blank">预览</el-link>
            <el-link type="primary" :href="row.downloadURL" style="margin-left: 10px">下载</el-link>
          </template>
        </el-table-column>
      </el-table>
      <el-empty v-else description="暂无附件" />
    </el-dialog>
    <!-- 打印预览弹窗 -->
    <el-dialog
      v-model="printPreviewVisible"
@@ -1062,6 +1169,15 @@
              />
            </el-form-item>
          </el-col>
          <el-col :span="24" v-if="deliveryForm.type === '货车'">
            <el-form-item label="出库批号:" prop="outboundBatches">
              <el-input
                v-model="deliveryForm.outboundBatches"
                placeholder="请输入出库批号"
                clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="24" v-else>
            <el-form-item label="快递公司:" prop="expressCompany">
              <el-input
@@ -1180,12 +1296,14 @@
} from "@/api/salesManagement/salesLedger.js";
import { getStockInventoryByModelId } from "@/api/inventoryManagement/stockInventory.js";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import { purchaseList } from "@/api/procurementManagement/procurementLedger.js";
import useFormData from "@/hooks/useFormData.js";
import dayjs from "dayjs";
import FileUpload from "@/components/AttachmentUpload/file/index.vue";
import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
import { getCurrentDate } from "@/utils/index.js";
import { listCustomer } from "@/api/basicData/customer.js";
import { getCustomerContractList, getContractFilesByNo } from "@/api/basicData/customerContract.js";
const FileList = defineAsyncComponent(() =>
  import("@/components/Dialog/FileList.vue")
@@ -1204,6 +1322,7 @@
const customerOption = ref([]);
const productOptions = ref([]);
const modelOptions = ref([]);
const purchaseContractOptions = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
@@ -1212,6 +1331,11 @@
const total = ref(0);
const fileList = ref([]);
const deliveryFileList = ref([]);
// 合同列表(供下拉选择)
const contractList = ref([]);
// 总合同附件弹窗
const contractFileDialogVisible = ref(false);
const contractFileList = ref([]);
// 用户信息表单弹框数据
const operationType = ref("");
@@ -1220,6 +1344,7 @@
  searchForm: {
    customerName: "", // 客户名称
    salesContractNo: "", // 销售合同编号
    masterContractNo: "", // 总合同号
    entryDate: null, // 录入日期
    entryDateStart: undefined,
    entryDateEnd: undefined,
@@ -1237,6 +1362,8 @@
    executionDate: "",
    hasProductionRecord: false,
    createTime: "",
    masterContractNo: "",
    purchaseContractNumber: "",
  },
  rules: {
    salesman: [{ required: true, message: "请选择", trigger: "change" }],
@@ -1264,7 +1391,7 @@
    taxInclusiveTotalPrice: "",
    taxExclusiveTotalPrice: "",
    invoiceType: "",
    isProduction: false,
    isProduction: false, // 默认值为 false(否)
  },
  productRules: {
    productCategory: [{ required: true, message: "请选择", trigger: "change" }],
@@ -1375,22 +1502,9 @@
const getDeliveryBatchNoList = async (productModelId) => {
  if (!productModelId) return [];
  const res = await getStockInventoryByModelId(productModelId);
  const rawList = Array.isArray(res?.data)
    ? res.data
    : res?.data?.records || res?.data?.rows || [];
  const rawList = res.data || [];
  const seenIds = new Set();
  return rawList
    .filter((item) => {
      if (!item?.id || !item?.batchNo || seenIds.has(item.id)) {
        return false;
      }
      seenIds.add(item.id);
      return true;
    })
    .map((item) => ({
      ...item,
      deliveryQuantity: 0,
    }));
};
const validateDeliveryShippingCarNumber = (_rule, value, callback) => {
  if (deliveryForm.value.type === "货车" && !value) {
@@ -1410,6 +1524,7 @@
    expressCompany: "",
    expressNumber: "",
    type: "货车", // 货车, 快递
    outboundBatches: "",
  },
  deliveryRules: {
    shippingCarNumber: [
@@ -1729,10 +1844,6 @@
};
// 打开弹框
const openForm = async (type, row) => {
  if (type === "edit" && row && !canEditLedger(row)) {
    proxy.$modal.msgWarning("当前系统登录人不是维护人,不能编辑数据");
    return;
  }
  operationType.value = type;
  form.value = {};
  productData.value = [];
@@ -1742,6 +1853,8 @@
  listCustomer({ current: -1, size: -1, type: 0 }).then((res) => {
    customerOption.value = res.data.records;
  });
  // 获取采购合同列表
  await getPurchaseContractList();
  form.value.entryPerson = userStore.id;
  if (type === "add") {
    // 新增时设置录入日期为当天
@@ -1749,18 +1862,29 @@
    // 签订日期默认为当天
    form.value.executionDate = getCurrentDate();
    // 创建时间默认为当天
    form.value.createTime = getCurrentDate();
    // 默认自动生成销售合同号
    form.value.createTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
    // 默认自动生成订单号
    form.value.autoGenerateContractNo = true;
  } else {
    currentId.value = row.id;
    getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
    getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(async (res) => {
      form.value = { ...res };
      form.value.entryPerson = Number(res.entryPerson);
      productData.value = form.value.productData;
      fileList.value = form.value.storageBlobVOs;
      // 编辑时设置自动生成为false,允许手动修改
      form.value.autoGenerateContractNo = false;
      // 编辑时加载客户的合同列表以便回显总合同号
      if (res.customerId) {
        try {
          const contractRes = await getCustomerContractList(res.customerId);
          if (contractRes.code === 200) {
            contractList.value = contractRes.data || [];
          }
        } catch (error) {
          console.error('获取客户合同列表失败:', error);
        }
      }
    });
  }
  // let userAll = await userStore.getInfo()
@@ -1871,7 +1995,7 @@
      taxInclusiveTotalPrice: taxInclusiveTotalPrice,
      taxExclusiveTotalPrice: taxExclusiveTotalPrice,
      invoiceType: "增普票",
      isProduction: true,
      isProduction: false, // 默认值为 false(否)
      productId: p.productId,
      productModelId: p.productModelId,
    };
@@ -1927,7 +2051,7 @@
  productOperationType.value = type;
  productForm.value = {};
  if (type === "add") {
    productForm.value.isProduction = true;
    productForm.value.isProduction = false; // 默认值为 false(否)
  }
  proxy.resetForm("productFormRef");
  if (type === "edit") {
@@ -1962,6 +2086,17 @@
    getProductOptions();
  }
  productFormVisible.value = true;
};
// 获取采购合同列表
const getPurchaseContractList = async () => {
  try {
    const res = await purchaseList({ current: -1, size: -1 });
    purchaseContractOptions.value = res.rows;
  } catch (error) {
    console.error("获取采购合同列表失败", error);
    purchaseContractOptions.value = [];
  }
};
// 提交产品表单
const submitProduct = () => {
@@ -2085,7 +2220,7 @@
  return status === "已发货" || status === "审核通过";
};
/** 判断销售订单下是否存在已发货/发货完成的产品(不可删除) */
/** 判断订单号下是否存在已发货/发货完成的产品(不可删除) */
const hasShippedProducts = (products) => {
  if (!products || !products.length) return false;
  return products.some((p) => {
@@ -2114,7 +2249,7 @@
  }
  const ids = selectedRows.value.map((item) => item.id);
  // 检查是否有已进行发货或发货完成的销售订单,若有则不允许删除
  // 检查是否有已进行发货或发货完成的订单号,若有则不允许删除
  const cannotDeleteNames = [];
  for (const row of selectedRows.value) {
    let products =
@@ -2133,7 +2268,7 @@
  }
  if (cannotDeleteNames.length > 0) {
    proxy.$modal.msgWarning(
      "已进行发货或发货完成的销售订单不能删除:" + cannotDeleteNames.join("、")
      "已进行发货或发货完成的订单号不能删除:" + cannotDeleteNames.join("、")
    );
    return;
  }
@@ -2155,7 +2290,7 @@
};
// 打印功能
const handlePrint = async () => {
  const handlePrint = async () => {
  if (selectedRows.value.length === 0) {
    proxy.$modal.msgWarning("请选择要打印的数据");
    return;
@@ -2512,11 +2647,7 @@
// 格式化日期
const formatDate = (dateString) => {
  if (!dateString) return getCurrentDate();
  const date = new Date(dateString);
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  return `${year}/${month}/${day}`;
  return dayjs(dateString).format("YYYY/MM/DD HH:mm:ss");
};
// 格式化日期时间
const formatDateTime = (date) => {
@@ -2860,6 +2991,7 @@
    type: "货车",
    batchNo: [],
    batchNoList,
    outboundBatches: "",
  };
  deliveryFileList.value = [];
  deliveryFormVisible.value = true;
@@ -2902,6 +3034,10 @@
        shippingCarNumber:
          deliveryForm.value.type === "货车"
            ? deliveryForm.value.shippingCarNumber
            : "",
        outboundBatches:
          deliveryForm.value.type === "货车"
            ? deliveryForm.value.outboundBatches
            : "",
        expressCompany:
          deliveryForm.value.type === "快递"
@@ -2971,6 +3107,59 @@
  let res = await userStore.getInfo();
  currentFactoryName.value = res.user.currentFactoryName;
};
// 获取退货状态标签类型
const getReturnStatusType = (returnStatus) => {
  const statusMap = {
    '无退货': 'success',
    '部分退货': 'warning',
    '全部退货': 'danger',
  };
  return statusMap[returnStatus] || 'info';
};
// 客户选择变化时,加载该客户的合同列表
const handleCustomerChange = async (customerId) => {
  form.value.masterContractNo = '';
  contractList.value = [];
  if (!customerId) return;
  try {
    const res = await getCustomerContractList(customerId);
    if (res.code === 200) {
      contractList.value = res.data || [];
    }
  } catch (error) {
    console.error('获取客户合同列表失败:', error);
  }
};
// 查看总合同附件
const openContractFileDialog = async (row) => {
  if (!row.masterContractNo) {
    proxy.$modal.msgWarning('该记录没有总合同号');
    return;
  }
  try {
    const res = await getContractFilesByNo(row.masterContractNo);
    if (res.code === 200) {
      contractFileList.value = res.data || [];
      contractFileDialogVisible.value = true;
    }
  } catch (error) {
    console.error('获取合同附件失败:', error);
  }
};
// 格式化文件大小
const formatFileSize = (bytes) => {
  if (!bytes) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
onMounted(() => {
  searchForm.salesContractNo = route.query.salesContractNo;
  getList();
@@ -3179,4 +3368,4 @@
    page-break-after: avoid;
  }
}
</style>
</style>