gaoluyang
2026-08-06 377c0a70c094d024aeb0bb94f4b791c6d5530c1e
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,20 +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="!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>
@@ -307,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;
@@ -362,6 +404,7 @@
                clearable
                :disabled="operationType === 'view'"
                filterable
                @change="handleCustomerChange"
              >
                <el-option
                  v-for="item in customerOption"
@@ -377,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"
@@ -386,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
@@ -402,18 +463,25 @@
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="付款方式">
              <el-input
                v-model="form.paymentMethod"
                placeholder="请输入"
                clearable
                :disabled="operationType === 'view'"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="付款方式">
              <el-select
                v-model="form.paymentMethod"
                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
@@ -497,8 +565,7 @@
              v-if="operationType !== 'view'"
              plain
              type="danger"
              @click="deleteProduct"
              >删除
              @click="deleteProduct">删除
            </el-button>
          </el-form-item>
        </el-row>
@@ -894,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"
@@ -1213,6 +1303,7 @@
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")
@@ -1240,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("");
@@ -1248,6 +1344,7 @@
  searchForm: {
    customerName: "", // 客户名称
    salesContractNo: "", // 销售合同编号
    masterContractNo: "", // 总合同号
    entryDate: null, // 录入日期
    entryDateStart: undefined,
    entryDateEnd: undefined,
@@ -1265,6 +1362,7 @@
    executionDate: "",
    hasProductionRecord: false,
    createTime: "",
    masterContractNo: "",
    purchaseContractNumber: "",
  },
  rules: {
@@ -1746,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 = [];
@@ -1769,17 +1863,28 @@
    form.value.executionDate = getCurrentDate();
    // 创建时间默认为当天
    form.value.createTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
    // 默认自动生成销售合同号
    // 默认自动生成订单号
    form.value.autoGenerateContractNo = true;
  } else {
    currentId.value = row.id;
    getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
    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()
@@ -2115,7 +2220,7 @@
  return status === "已发货" || status === "审核通过";
};
/** 判断销售订单下是否存在已发货/发货完成的产品(不可删除) */
/** 判断订单号下是否存在已发货/发货完成的产品(不可删除) */
const hasShippedProducts = (products) => {
  if (!products || !products.length) return false;
  return products.some((p) => {
@@ -2144,7 +2249,7 @@
  }
  const ids = selectedRows.value.map((item) => item.id);
  // 检查是否有已进行发货或发货完成的销售订单,若有则不允许删除
  // 检查是否有已进行发货或发货完成的订单号,若有则不允许删除
  const cannotDeleteNames = [];
  for (const row of selectedRows.value) {
    let products =
@@ -2163,7 +2268,7 @@
  }
  if (cannotDeleteNames.length > 0) {
    proxy.$modal.msgWarning(
      "已进行发货或发货完成的销售订单不能删除:" + cannotDeleteNames.join("、")
      "已进行发货或发货完成的订单号不能删除:" + cannotDeleteNames.join("、")
    );
    return;
  }
@@ -3002,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();