huminmin
2026-06-01 a563ea879ef5fb6897e76d2df661e465dce2ab9b
src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue
@@ -3,32 +3,44 @@
  <div class="approve-detail-panel">
    <div class="detail-block">
      <div class="detail-block-title">基本信息</div>
      <el-descriptions :column="2"
                       border>
        <el-descriptions-item label="业务单号">{{ row.bizId || row.id || "—" }}</el-descriptions-item>
      <el-descriptions :column="2" border>
        <el-descriptions-item label="业务单号">{{
          row.bizId || row.id || "—"
        }}</el-descriptions-item>
        <el-descriptions-item label="审批状态">
          <el-tag :type="approvalStatusTagType(row.approvalStatus)"
                  size="small"
                  effect="plain">
          <el-tag
            :type="approvalStatusTagType(row.approvalStatus)"
            size="small"
            effect="plain"
          >
            {{ approvalStatusLabel(row.approvalStatus) }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="审批类型">
          <span class="approve-type-cell"
                :style="approvalTypeStyle(row.approvalType)">
          <span
            class="approve-type-cell"
            :style="approvalTypeStyle(row.approvalType)"
          >
            {{ approvalTypeLabel(row.approvalType) }}
          </span>
        </el-descriptions-item>
        <el-descriptions-item label="申请人编号">{{ row.applicantNo || "—" }}</el-descriptions-item>
        <el-descriptions-item label="申请人名称">{{ row.applicantName || "—" }}</el-descriptions-item>
        <el-descriptions-item label="申请摘要">{{ row.summary || "—" }}</el-descriptions-item>
        <el-descriptions-item v-if="row.rejectReason"
                              label="驳回原因"
                              :span="2">
        <el-descriptions-item label="申请人编号">{{
          row.applicantNo || "—"
        }}</el-descriptions-item>
        <el-descriptions-item label="申请人名称">{{
          row.applicantName || "—"
        }}</el-descriptions-item>
        <el-descriptions-item label="申请摘要">{{
          row.summary || "—"
        }}</el-descriptions-item>
        <el-descriptions-item
          v-if="row.rejectReason"
          label="驳回原因"
          :span="2"
        >
          <span class="reject-text">{{ row.rejectReason }}</span>
        </el-descriptions-item>
        <el-descriptions-item label="创建时间"
                              :span="2">
        <el-descriptions-item label="创建时间" :span="2">
          {{ formatDisplayTime(row.createTime) }}
        </el-descriptions-item>
      </el-descriptions>
@@ -36,141 +48,226 @@
    <div class="detail-block">
      <div class="detail-block-title">填报内容</div>
      <!-- 默认表单展示 -->
      <FormPayloadFields v-if="!isSpecialApprovalType"
                         :fields="formResolved.fields"
                         :form-payload="formResolved.formPayload"
                         readonly />
      <FormPayloadFields
        v-if="!isSpecialApprovalType"
        :fields="formResolved.fields"
        :form-payload="formResolved.formPayload"
        readonly
      />
      <!-- 发货审批详情 -->
      <template v-else-if="row.businessType === 7">
        <div v-if="detailData.shippingInfo" class="shipment-detail">
          <el-divider content-position="left">发货详情</el-divider>
          <el-descriptions :column="2" border>
            <el-descriptions-item label="销售订单">{{ detailData.shippingInfo.salesContractNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货订单号">{{ detailData.shippingInfo.shippingNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="客户名称">{{ detailData.shippingInfo.customerName || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货类型">{{ detailData.shippingInfo.type || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货日期">{{ detailData.shippingInfo.shippingDateDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="审核状态">{{ detailData.shippingInfo.status || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货车牌号">{{ detailData.shippingInfo.shippingCarNumber || "--" }}</el-descriptions-item>
            <el-descriptions-item label="快递公司">{{ detailData.shippingInfo.expressCompany || "--" }}</el-descriptions-item>
            <el-descriptions-item label="快递单号" :span="2">{{ detailData.shippingInfo.expressNumber || "--" }}</el-descriptions-item>
            <el-descriptions-item label="销售订单">{{
              detailData.shippingInfo.salesContractNo || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="出库批号">{{
              detailData.shippingInfo.outboundBatches || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="客户名称">{{
              detailData.shippingInfo.customerName || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="发货类型">{{
              detailData.shippingInfo.type || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="发货日期">{{
              detailData.shippingInfo.shippingDateDate || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="审核状态">{{
              detailData.shippingInfo.status || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="发货车牌号">{{
              detailData.shippingInfo.shippingCarNumber || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="快递公司">{{
              detailData.shippingInfo.expressCompany || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="快递单号" :span="2">{{
              detailData.shippingInfo.expressNumber || "--"
            }}</el-descriptions-item>
          </el-descriptions>
          <div v-if="detailData.shippingProductDetailDtoList.length" style="margin-top: 20px;">
          <div
            v-if="detailData.shippingProductDetailDtoList.length"
            style="margin-top: 20px"
          >
            <h4>产品明细</h4>
            <el-table :data="detailData.shippingProductDetailDtoList"
                      border
                      size="small"
                      style="width: 100%">
              <el-table-column label="批号" prop="batchNo" min-width="160" show-overflow-tooltip />
              <el-table-column label="产品名称" prop="productName" min-width="160" show-overflow-tooltip />
              <el-table-column label="规格型号" prop="specificationModel" min-width="160" show-overflow-tooltip />
              <el-table-column label="发货数量" prop="deliveryQuantity" min-width="120" align="center" />
            <el-table
              :data="detailData.shippingProductDetailDtoList"
              border
              size="small"
              style="width: 100%"
            >
              <el-table-column
                label="批号"
                prop="batchNo"
                min-width="160"
                show-overflow-tooltip
              />
              <el-table-column
                label="产品名称"
                prop="productName"
                min-width="160"
                show-overflow-tooltip
              />
              <el-table-column
                label="规格型号"
                prop="specificationModel"
                min-width="160"
                show-overflow-tooltip
              />
              <el-table-column
                label="发货数量"
                prop="deliveryQuantity"
                min-width="120"
                align="center"
              />
            </el-table>
          </div>
        </div>
      </template>
      <!-- 采购审批详情 -->
      <template v-else-if="row.businessType === 5">
        <div v-if="detailData" class="procurement-detail">
          <el-divider content-position="left">采购详情</el-divider>
          <el-descriptions :column="2" border>
            <el-descriptions-item label="采购合同号">{{ detailData.purchaseContractNumber || "--" }}</el-descriptions-item>
            <el-descriptions-item label="供应商名称">{{ detailData.supplierName || "--" }}</el-descriptions-item>
            <el-descriptions-item label="项目名称">{{ detailData.projectName || "--" }}</el-descriptions-item>
            <el-descriptions-item label="销售合同号">{{ detailData.salesContractNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="签订日期">{{ detailData.executionDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="录入日期">{{ detailData.entryDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="付款方式">{{ detailData.paymentMethod || "--" }}</el-descriptions-item>
            <el-descriptions-item label="采购合同号">{{
              detailData.purchaseContractNumber || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="供应商名称">{{
              detailData.supplierName || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="项目名称">{{
              detailData.projectName || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="销售合同号">{{
              detailData.salesContractNo || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="签订日期">{{
              detailData.executionDate || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="录入日期">{{
              detailData.entryDate || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="付款方式">{{
              detailData.paymentMethod || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="合同金额" :span="2">
              <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
              <span style="font-size: 18px; color: #e6a23c; font-weight: bold">
                ¥{{ Number(detailData.contractAmount ?? 0).toFixed(2) }}
              </span>
            </el-descriptions-item>
          </el-descriptions>
          <div v-if="detailData.productData.length" style="margin-top: 20px;">
          <div v-if="detailData.productData.length" style="margin-top: 20px">
            <h4>产品明细</h4>
            <el-table :data="detailData.productData"
                      border
                      style="width: 100%">
            <el-table :data="detailData.productData" 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>
                <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>
                <template #default="scope"
                  >¥{{
                    Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2)
                  }}</template
                >
              </el-table-column>
            </el-table>
          </div>
        </div>
      </template>
      <!-- 报价审批详情 -->
      <template v-else-if="row.businessType === 6">
        <div v-if="detailData" class="quotation-detail">
          <el-divider content-position="left">报价详情</el-divider>
          <el-descriptions :column="2" border>
            <el-descriptions-item label="报价单号">{{ detailData.quotationNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="客户名称">{{ detailData.customer || "--" }}</el-descriptions-item>
            <el-descriptions-item label="业务员">{{ detailData.salesperson || "--" }}</el-descriptions-item>
            <el-descriptions-item label="报价日期">{{ detailData.quotationDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="有效期至">{{ detailData.validDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="付款方式">{{ detailData.paymentMethod || "--" }}</el-descriptions-item>
            <el-descriptions-item label="报价单号">{{
              detailData.quotationNo || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="客户名称">{{
              detailData.customer || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="业务员">{{
              detailData.salesperson || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="报价日期">{{
              detailData.quotationDate || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="有效期至">{{
              detailData.validDate || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="付款方式">{{
              detailData.paymentMethod || "--"
            }}</el-descriptions-item>
            <el-descriptions-item label="报价总额" :span="2">
              <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
              <span style="font-size: 18px; color: #e6a23c; font-weight: bold">
                ¥{{ Number(detailData.totalAmount ?? 0).toFixed(2) }}
              </span>
            </el-descriptions-item>
          </el-descriptions>
          <div v-if="detailData.products?.length" style="margin-top: 20px;">
          <div v-if="detailData.products?.length" style="margin-top: 20px">
            <h4>产品明细</h4>
            <el-table :data="detailData.products"
                      border
                      style="width: 100%">
            <el-table :data="detailData.products" border style="width: 100%">
              <el-table-column prop="product" label="产品名称" />
              <el-table-column prop="specification" label="规格型号" />
              <el-table-column prop="unit" label="单位" />
              <el-table-column prop="unitPrice" label="单价">
                <template #default="scope">¥{{ Number(scope.row.unitPrice ?? 0).toFixed(2) }}</template>
                <template #default="scope"
                  >¥{{ Number(scope.row.unitPrice ?? 0).toFixed(2) }}</template
                >
              </el-table-column>
            </el-table>
          </div>
          <div v-if="detailData.remark" style="margin-top: 20px;">
          <div v-if="detailData.remark" style="margin-top: 20px">
            <h4>备注</h4>
            <p>{{ detailData.remark }}</p>
          </div>
        </div>
      </template>
    </div>
    <div v-if="attachmentList.length"
         class="detail-block">
    <div v-if="attachmentList.length" class="detail-block">
      <div class="detail-block-title">附件列表</div>
      <div class="attachment-list">
        <div v-for="file in attachmentList"
             :key="file.id"
             class="attachment-item">
        <div
          v-for="file in attachmentList"
          :key="file.id"
          class="attachment-item"
        >
          <el-icon class="file-icon">
            <Paperclip />
          </el-icon>
          <span class="file-name"
                :title="file.name || file.originalFilename">
          <span class="file-name" :title="file.name || file.originalFilename">
            {{ file.name || file.originalFilename }}
          </span>
          <div class="file-actions">
            <el-link v-if="file.previewURL || file.url"
                     type="primary"
                     :underline="false"
                     @click="openFile(file.previewURL || file.url)">预览</el-link>
            <el-divider v-if="(file.previewURL || file.url) && file.downloadURL"
                        direction="vertical" />
            <el-link v-if="file.downloadURL"
                     type="primary"
                     :underline="false"
                     @click="openFile(file.downloadURL)">下载</el-link>
            <el-link
              v-if="file.previewURL || file.url"
              type="primary"
              :underline="false"
              @click="openFile(file.previewURL || file.url)"
              >预览</el-link
            >
            <el-divider
              v-if="(file.previewURL || file.url) && file.downloadURL"
              direction="vertical"
            />
            <el-link
              v-if="file.downloadURL"
              type="primary"
              :underline="false"
              @click="openFile(file.downloadURL)"
              >下载</el-link
            >
          </div>
        </div>
      </div>
@@ -179,108 +276,107 @@
</template>
<script setup>
  import { computed } from "vue";
  import { Paperclip } from "@element-plus/icons-vue";
  import { formatDisplayTime } from "../../approve-template/approveTemplateConstants.js";
  import {
    approvalTypeLabel,
    approvalTypeStyle,
    approvalStatusLabel,
    approvalStatusTagType,
    resolveInstanceFormFields,
  } from "../approveListConstants.js";
  import FormPayloadFields from "./FormPayloadFields.vue";
import { computed } from "vue";
import { Paperclip } from "@element-plus/icons-vue";
import { formatDisplayTime } from "../../approve-template/approveTemplateConstants.js";
import {
  approvalTypeLabel,
  approvalTypeStyle,
  approvalStatusLabel,
  approvalStatusTagType,
  resolveInstanceFormFields,
} from "../approveListConstants.js";
import FormPayloadFields from "./FormPayloadFields.vue";
  const props = defineProps({
    row: { type: Object, default: () => ({}) },
    detailData: { type: Object, default: () => ({}) },
  });
const props = defineProps({
  row: { type: Object, default: () => ({}) },
  detailData: { type: Object, default: () => ({}) },
});
  const formResolved = computed(() => resolveInstanceFormFields(props.row));
const formResolved = computed(() => resolveInstanceFormFields(props.row));
// 是否为特殊审批类型(采购、发货、报价)
const isSpecialApprovalType = computed(() => {
  return [5, 7, 6].includes(props.row.businessType);
});
  // 是否为特殊审批类型(采购、发货、报价)
  const isSpecialApprovalType = computed(() => {
    return [5, 7, 6].includes(props.row.businessType);
  });
// 详情数据(直接使用传入的 detail-data 参数)
const detailData = computed(() => {
  return props.detailData || {};
});
  // 详情数据(直接使用传入的 detail-data 参数)
  const detailData = computed(() => {
    return props.detailData || {};
  });
const attachmentList = computed(() => {
  const list = props.row.storageBlobVOList || props.row.storageBlobDTOs || [];
  return Array.isArray(list) ? list : [];
});
  const attachmentList = computed(() => {
    const list = props.row.storageBlobVOList || props.row.storageBlobDTOs || [];
    return Array.isArray(list) ? list : [];
  });
  function openFile(url) {
    if (!url) return;
    window.open(url, "_blank");
  }
function openFile(url) {
  if (!url) return;
  window.open(url, "_blank");
}
</script>
<style scoped>
  .approve-detail-panel {
    display: flex;
    flex-direction: column;
    gap: 20px;
  }
  .detail-block-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--el-text-color-primary);
    margin: 0 0 12px;
    padding-left: 10px;
    border-left: 3px solid var(--el-color-primary);
    line-height: 1.4;
  }
  .approve-type-cell {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 4px;
    font-size: 13px;
    line-height: 1.5;
  }
  .reject-text {
    color: var(--el-color-danger);
  }
.approve-detail-panel {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.detail-block-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--el-text-color-primary);
  margin: 0 0 12px;
  padding-left: 10px;
  border-left: 3px solid var(--el-color-primary);
  line-height: 1.4;
}
.approve-type-cell {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 4px;
  font-size: 13px;
  line-height: 1.5;
}
.reject-text {
  color: var(--el-color-danger);
}
  .attachment-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 12px;
  }
  .attachment-item {
    display: flex;
    align-items: center;
    padding: 10px 12px;
    background-color: var(--el-fill-color-light);
    border-radius: 6px;
    border: 1px solid var(--el-border-color-lighter);
    transition: all 0.3s;
  }
  .attachment-item:hover {
    border-color: var(--el-color-primary-light-5);
    background-color: var(--el-color-primary-light-9);
  }
  .file-icon {
    font-size: 18px;
    color: var(--el-text-color-secondary);
    margin-right: 10px;
  }
  .file-name {
    flex: 1;
    font-size: 13px;
    color: var(--el-text-color-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-right: 12px;
  }
  .file-actions {
    display: flex;
    align-items: center;
    flex-shrink: 0;
  }
</style>
.attachment-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 12px;
}
.attachment-item {
  display: flex;
  align-items: center;
  padding: 10px 12px;
  background-color: var(--el-fill-color-light);
  border-radius: 6px;
  border: 1px solid var(--el-border-color-lighter);
  transition: all 0.3s;
}
.attachment-item:hover {
  border-color: var(--el-color-primary-light-5);
  background-color: var(--el-color-primary-light-9);
}
.file-icon {
  font-size: 18px;
  color: var(--el-text-color-secondary);
  margin-right: 10px;
}
.file-name {
  flex: 1;
  font-size: 13px;
  color: var(--el-text-color-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-right: 12px;
}
.file-actions {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}
</style>