zhangwencui
4 天以前 f670b79094c95d791fc43c8fc8b5858ebf8426dc
src/pages/oa/ApproveManage/approve-list/_components/ApproveInstanceDetailBody.vue
@@ -50,30 +50,46 @@
        </view>
      </view>
    </view>
    <view class="section-card">
      <view class="section-head">
        <text class="section-title">填报内容</text>
        <text class="section-title">{{ isSpecialApprovalType ? specialDetailTitle : "填报内容" }}</text>
      </view>
      <view v-if="displayFields.length"
            class="info-rows">
        <view v-for="field in displayFields"
              :key="field.key"
              class="info-row">
          <text class="info-label">{{ field.label }}</text>
          <text class="info-value">{{ displayFieldValue(field) }}</text>
      <!-- 采购/报价/发货审批:展示业务单据详情(与 Web approve-list 一致) -->
      <template v-if="isSpecialApprovalType">
        <view v-if="businessDetailLoading"
              class="empty-hint">加载中...</view>
        <view v-else-if="!hasBusinessDetail"
              class="empty-hint">{{ specialDetailEmptyText }}</view>
        <view v-else
              class="info-rows">
          <view v-for="(item, idx) in specialDetailRows"
                :key="`special-${idx}`"
                class="info-row">
            <text class="info-label">{{ item.label }}</text>
            <text class="info-value">{{ item.value }}</text>
          </view>
        </view>
        <view v-for="(extra, idx) in moduleExtraRows"
              :key="`extra-${idx}`"
              class="info-row">
          <text class="info-label">{{ extra.label }}</text>
          <text class="info-value">{{ extra.value }}</text>
      </template>
      <template v-else>
        <view v-if="displayFields.length"
              class="info-rows">
          <view v-for="field in displayFields"
                :key="field.key"
                class="info-row">
            <text class="info-label">{{ field.label }}</text>
            <text class="info-value">{{ displayFieldValue(field) }}</text>
          </view>
          <view v-for="(extra, idx) in moduleExtraRows"
                :key="`extra-${idx}`"
                class="info-row">
            <text class="info-label">{{ extra.label }}</text>
            <text class="info-value">{{ extra.value }}</text>
          </view>
        </view>
      </view>
      <view v-else
            class="empty-hint">暂无填报内容</view>
        <view v-else
              class="empty-hint">暂无填报内容</view>
      </template>
    </view>
    <view class="section-card">
      <view class="section-head">
        <text class="section-title">审批流程({{ flowNodes.length }} 项)</text>
@@ -112,7 +128,6 @@
      <view v-else
            class="empty-hint">暂无流程节点</view>
    </view>
    <view class="section-card">
      <view class="section-head">
        <text class="section-title">审批记录</text>
@@ -140,8 +155,11 @@
</template>
<script setup>
  import { computed } from "vue";
  import { computed, ref, watch } from "vue";
  import { APPROVAL_MODULE_KEYS } from "../../../_utils/approvalModuleRegistry.js";
  import { getQuotationList } from "@/api/salesManagement/salesQuotation";
  import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger";
  import { getDeliveryDetailByShippingNo } from "@/api/collaborativeApproval/approvalProcess";
  import {
    computeLeaveDurationDisplay,
    computeOvertimeHoursDisplay,
@@ -168,7 +186,19 @@
    moduleKey: { type: String, default: "" },
  });
  const LEVEL_TEXT = ["", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"];
  const LEVEL_TEXT = [
    "",
    "一",
    "二",
    "三",
    "四",
    "五",
    "六",
    "七",
    "八",
    "九",
    "十",
  ];
  const isBusinessModule = computed(() =>
    [
@@ -181,10 +211,14 @@
  );
  const statusLabel = status =>
    isBusinessModule.value ? businessStatusText(status) : instanceStatusText(status);
    isBusinessModule.value
      ? businessStatusText(status)
      : instanceStatusText(status);
  const statusTagType = status =>
    isBusinessModule.value ? businessStatusTagType(status) : instanceStatusTagType(status);
    isBusinessModule.value
      ? businessStatusTagType(status)
      : instanceStatusTagType(status);
  const displayFields = computed(() => resolveInstanceDisplayFields(props.row));
@@ -216,15 +250,166 @@
  const flowNodes = computed(() => mapTasksToFlowNodes(props.row?.tasks));
  const approvalRecords = computed(() =>
    mapApprovalRecords(props.row?.records)
  );
  const approvalRecords = computed(() => mapApprovalRecords(props.row?.records));
  const rejectReason = computed(() =>
    getRejectReasonFromRecords(props.row?.records)
  );
  const levelLabel = n => LEVEL_TEXT[Number(n)] || String(n);
  /** 采购/报价/发货审批:业务单据详情(与 Web approve-list 一致) */
  const SPECIAL_BUSINESS_TYPES = [5, 6, 7];
  const businessType = computed(() => Number(props.row?.businessType));
  const isSpecialApprovalType = computed(() =>
    SPECIAL_BUSINESS_TYPES.includes(businessType.value)
  );
  const businessDetail = ref({});
  const businessProductList = ref([]);
  const businessDetailLoading = ref(false);
  const specialDetailTitle = computed(() => {
    if (businessType.value === 5) return "采购详情";
    if (businessType.value === 6) return "报价详情";
    return "发货详情";
  });
  const specialDetailEmptyText = computed(() => {
    if (businessType.value === 5) return "未查询到对应采购详情";
    if (businessType.value === 6) return "未查询到对应报价详情";
    return "未查询到对应发货详情";
  });
  const hasBusinessDetail = computed(() => {
    const d = businessDetail.value || {};
    if (businessType.value === 5) return Boolean(d.purchaseContractNumber);
    if (businessType.value === 6) return Boolean(d.quotationNo);
    if (businessType.value === 7) return Boolean(d.shippingInfo);
    return false;
  });
  const formatMoney = val => `¥${Number(val ?? 0).toFixed(2)}`;
  const joinDesc = parts => parts.filter(Boolean).join(" · ");
  const specialDetailRows = computed(() => {
    const d = businessDetail.value || {};
    const products = businessProductList.value || [];
    const rows = [];
    const push = (label, value) => rows.push({ label, value: value || "--" });
    if (businessType.value === 6) {
      push("报价单号", d.quotationNo);
      push("客户名称", d.customer);
      push("业务员", d.salesperson);
      push("报价日期", d.quotationDate);
      push("有效期至", d.validDate);
      push("付款方式", d.paymentMethod);
      push("报价总额", formatMoney(d.totalAmount));
      products.forEach((p, i) => {
        push(
          p.product || `产品${i + 1}`,
          joinDesc([p.specification, p.unit, formatMoney(p.unitPrice)])
        );
      });
      if (d.remark) push("备注", d.remark);
    } else if (businessType.value === 5) {
      push("采购合同号", d.purchaseContractNumber);
      push("供应商名称", d.supplierName);
      push("项目名称", d.projectName);
      push("销售合同号", d.salesContractNo);
      push("签订日期", d.executionDate);
      push("录入日期", d.entryDate);
      push("付款方式", d.paymentMethod);
      push("合同金额", formatMoney(d.contractAmount));
      products.forEach((p, i) => {
        push(
          p.productCategory || `产品${i + 1}`,
          joinDesc([
            p.specificationModel,
            p.quantity != null && p.quantity !== ""
              ? `${p.quantity}${p.unit || ""}`
              : "",
            `含税单价 ${formatMoney(p.taxInclusiveUnitPrice)}`,
            `含税总价 ${formatMoney(p.taxInclusiveTotalPrice)}`,
          ])
        );
      });
    } else if (businessType.value === 7) {
      const info = d.shippingInfo || {};
      push("销售订单", info.salesContractNo);
      push("发货订单号", info.shippingNo);
      push("客户名称", info.customerName);
      push("发货类型", info.type);
      push("发货日期", info.shippingDate);
      push("审核状态", info.status);
      push("发货车牌号", info.shippingCarNumber);
      push("快递公司", info.expressCompany);
      push("快递单号", info.expressNumber);
      products.forEach((p, i) => {
        push(
          p.productName || `产品${i + 1}`,
          joinDesc([
            p.batchNo ? `批号 ${p.batchNo}` : "",
            p.specificationModel,
            p.deliveryQuantity != null ? `发货数量 ${p.deliveryQuantity}` : "",
          ])
        );
      });
    }
    return rows;
  });
  async function loadBusinessDetail() {
    const row = props.row || {};
    const type = Number(row.businessType);
    businessDetail.value = {};
    businessProductList.value = [];
    if (!SPECIAL_BUSINESS_TYPES.includes(type)) return;
    businessDetailLoading.value = true;
    try {
      if (type === 6) {
        if (!row.quotationNo) return;
        const res = await getQuotationList({ quotationNo: row.quotationNo });
        const hit = res?.data?.records?.[0] || {};
        businessDetail.value = hit;
        businessProductList.value = hit.products || [];
      } else if (type === 5) {
        if (!row.purchaseContractNumber) return;
        const res = await getPurchaseByCode({
          purchaseContractNumber: row.purchaseContractNumber,
          approvalInstanceId: row.id,
        });
        const hit = res?.data || res || {};
        businessDetail.value = hit;
        businessProductList.value = hit.productData || [];
      } else if (type === 7) {
        if (!row.shippingNo) return;
        const res = await getDeliveryDetailByShippingNo({
          shippingNo: row.shippingNo,
        });
        const hit = res?.data || res || {};
        businessDetail.value = hit;
        businessProductList.value = hit.shippingProductDetailDtoList || [];
      }
    } catch {
      businessDetail.value = {};
      businessProductList.value = [];
    } finally {
      businessDetailLoading.value = false;
    }
  }
  watch(
    () => [props.row?.id, props.row?.businessType],
    () => {
      loadBusinessDetail();
    },
    { immediate: true }
  );
</script>
<style scoped lang="scss">