5 天以前 b59518d5c068ae8e6e32cce90ccf281bf81dc54a
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
@@ -39,39 +39,6 @@
                  </el-form-item>
               </el-col>
            </el-row>
            <!-- 审批人选择(动态节点) -->
            <el-row :gutter="30">
               <el-col :span="12">
                  <el-form-item label="申请人:" prop="approveUser">
                     <el-select
                        v-model="form.approveUser"
                        placeholder="选择人员"
                        disabled
                     >
                        <el-option
                           v-for="user in userList"
                           :key="user.userId"
                           :label="user.nickName"
                           :value="user.userId"
                        />
                     </el-select>
                  </el-form-item>
               </el-col>
               <el-col :span="12">
                  <el-form-item label="申请日期:" prop="approveTime">
                     <el-date-picker
                        v-model="form.approveTime"
                        type="date"
                        placeholder="请选择日期"
                        value-format="YYYY-MM-DD"
                        format="YYYY-MM-DD"
                        clearable
                        style="width: 100%"
                        disabled
                     />
                  </el-form-item>
               </el-col>
            </el-row>
         </el-form>
      <!-- 报价审批:展示报价详情(复用销售报价"查看详情对话框"内容结构) -->
@@ -115,19 +82,6 @@
              <div v-if="currentQuotation.remark" style="margin-top: 20px;">
                <h4>备注</h4>
                <p>{{ currentQuotation.remark }}</p>
              </div>
              <div v-if="quotationAttachments.length > 0" style="margin-top: 20px;">
                <h4>附件</h4>
                <el-table :data="quotationAttachments" border style="width: 100%">
                  <el-table-column prop="name" label="附件名称" min-width="360" show-overflow-tooltip />
                  <el-table-column label="操作" width="160" align="center">
                    <template #default="{ row }">
                      <el-button link type="primary" size="small" @click="downloadAttachment(row)">下载</el-button>
                      <el-button link type="primary" size="small" @click="previewAttachment(row)">预览</el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
            </template>
          </template>
@@ -173,6 +127,43 @@
                  </el-table-column>
                  <el-table-column prop="taxInclusiveTotalPrice" label="含税总价">
                    <template #default="scope">¥{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template>
                  </el-table-column>
                </el-table>
              </div>
            </template>
          </template>
        </el-skeleton>
      </div>
      <!-- 用印审批:展示用印申请详情 -->
      <div v-if="isSealApproval" style="margin: 10px 0 18px;">
        <el-divider content-position="left">用印详情</el-divider>
        <el-skeleton :loading="sealLoading" animated>
          <template #template>
            <el-skeleton-item variant="h3" style="width: 30%" />
            <el-skeleton-item variant="text" style="width: 100%" />
          </template>
          <template #default>
            <el-empty v-if="!currentSeal || !currentSeal.applicationNum" description="未查询到对应用印申请详情" />
            <template v-else>
              <el-descriptions :column="2" border>
                <el-descriptions-item label="申请编号">{{ currentSeal.applicationNum }}</el-descriptions-item>
                <el-descriptions-item label="申请标题">{{ currentSeal.title }}</el-descriptions-item>
                <el-descriptions-item label="用印类型">{{ getSealTypeText(currentSeal.sealType) }}</el-descriptions-item>
                <el-descriptions-item label="紧急程度">{{ getUrgencyText(currentSeal.urgency) }}</el-descriptions-item>
                <el-descriptions-item label="申请原因" :span="2">{{ currentSeal.reason }}</el-descriptions-item>
              </el-descriptions>
              <div v-if="currentSeal.commonFileList?.length" style="margin-top: 20px;">
                <h4>附件</h4>
                <el-table :data="currentSeal.commonFileList" border style="width: 100%">
                  <el-table-column label="附件名称" show-overflow-tooltip>
                    <template #default="scope">{{ scope.row.name }}</template>
                  </el-table-column>
                  <el-table-column label="操作" width="150" align="center">
                    <template #default="scope">
                      <el-button link type="primary" size="small" @click="previewSealFile(scope.row)">预览</el-button>
                      <el-button link type="primary" size="small" @click="downloadSealFile(scope.row)">下载</el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
@@ -242,11 +233,11 @@
   updateApproveNode
} from "@/api/collaborativeApproval/approvalProcess.js";
import useUserStore from "@/store/modules/user.js";
import {userListNoPageByTenantId} from "@/api/system/user.js";
import { WarningFilled, Edit, Check, MoreFilled } from '@element-plus/icons-vue'
import { getQuotationDetail, getQuotationList } from "@/api/salesManagement/salesQuotation.js";
import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js";
import filePreview from "@/components/filePreview/index.vue";
import { getSealDetail } from "@/api/collaborativeApproval/sealManagement.js";
import FilePreview from '@/components/filePreview/index.vue'
const emit = defineEmits(['close'])
const { proxy } = getCurrentInstance()
@@ -263,45 +254,20 @@
const formRef = ref(null);
const userStore = useUserStore()
const productOptions = ref([]);
const userList = ref([])
const quotationLoading = ref(false)
const currentQuotation = ref({})
const purchaseLoading = ref(false)
const currentPurchase = ref({})
const sealLoading = ref(false)
const currentSeal = ref({})
const filePreviewRef = ref()
const isQuotationApproval = computed(() => Number(props.approveType) === 6)
const isPurchaseApproval = computed(() => Number(props.approveType) === 5)
const normalizeQuotationFiles = (raw) => {
  const list =
    (raw && Array.isArray(raw.salesLedgerFiles) && raw.salesLedgerFiles) ||
    (raw && Array.isArray(raw.quotationFiles) && raw.quotationFiles) ||
    (raw && Array.isArray(raw.fileList) && raw.fileList) ||
    (raw && Array.isArray(raw.files) && raw.files) ||
    []
  return list
    .map((item) => ({
      id: item?.id,
      name: item?.fileName || item?.name || item?.originalName || item?.filename || "附件",
      url: item?.fileUrl || item?.url || item?.path || item?.tempPath,
    }))
    .filter((i) => i.url)
}
const quotationAttachments = computed(() => normalizeQuotationFiles(currentQuotation.value))
const downloadAttachment = (row) => {
  proxy.$download.name(row.url)
}
const previewAttachment = (row) => {
  filePreviewRef.value?.open?.(row.url)
}
const isSealApproval = computed(() => Number(props.approveType) === 9)
const data = reactive({
   form: {
      approveTime: "",
      approveId: "",
      approveUser: "",
      approveDeptId: "",
      approveReason: "",
      checkResult: "",
@@ -336,9 +302,6 @@
  dialogFormVisible.value = true;
  currentQuotation.value = {}
  currentPurchase.value = {}
   userListNoPageByTenantId().then((res) => {
      userList.value = res.data;
   });
   form.value = {...row}
   // 立即清除表单验证状态(因为字段是disabled的,不需要验证)
   nextTick(() => {
@@ -371,18 +334,9 @@
    const quotationNo = row?.approveReason;
    if (quotationNo) {
      quotationLoading.value = true
      getQuotationList({ quotationNo }).then(async (res) => {
      getQuotationList({ quotationNo }).then((res) => {
        const records = res?.data?.records || []
        const first = records[0] || {}
        currentQuotation.value = first
        if (first?.id && normalizeQuotationFiles(first).length === 0) {
          try {
            const detailRes = await getQuotationDetail({ id: first.id })
            const detail = detailRes?.data || detailRes || {}
            currentQuotation.value = { ...first, ...detail }
          } catch (e) {
          }
        }
        currentQuotation.value = records[0] || {}
      }).finally(() => {
        quotationLoading.value = false
      })
@@ -403,6 +357,19 @@
        purchaseLoading.value = false
      })
    }
  }
  // 用印审批:按审批流程 DB 主键(row.id)查用印申请详情
  if (isSealApproval.value) {
    sealLoading.value = true
    getSealDetail(row.id).then((res) => {
      currentSeal.value = res.data || {}
    }).catch((err) => {
      console.error('查询用印详情失败:', err)
      proxy.$modal.msgError('查询用印详情失败')
    }).finally(() => {
      sealLoading.value = false
    })
  }
  approveProcessDetails(row.approveId).then((res) => {
@@ -429,6 +396,42 @@
      productOptions.value = res.data;
   });
};
// 用印类型文本
const getSealTypeText = (sealType) => {
  const map = { official: '公章', contract: '合同专用章', finance: '财务专用章', legal: '法人章' }
  return map[sealType] || sealType || '未知'
}
// 紧急程度文本
const getUrgencyText = (urgency) => {
  const map = { normal: '普通', urgent: '紧急', 'very-urgent': '特急' }
  return map[urgency] || urgency || '未知'
}
// 预览附件(URL 为完整地址,原样打开,不拼 host)
const previewSealFile = (row) => {
  const url = row.previewURL || row.previewUrl || row.url
  if (url && filePreviewRef.value) {
    filePreviewRef.value.openUrl(url)
  } else {
    proxy.$modal.msgWarning('文件地址无效,无法预览')
  }
}
// 下载附件(锚点方式,URL 为完整地址)
const downloadSealFile = (row) => {
  const url = row.downloadURL || row.downloadUrl || row.url
  if (url) {
    const filename = row.originalFilename || row.name || row.fileName || 'download'
    const a = document.createElement('a')
    a.href = url
    a.download = filename
    a.target = '_blank'
    a.rel = 'noopener noreferrer'
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
  } else {
    proxy.$modal.msgWarning('文件地址无效,无法下载')
  }
}
// 提交审批
const submitForm = (status) => {
  const filteredActivities = activities.value.filter(activity => activity.isShen);
@@ -457,6 +460,8 @@
  currentQuotation.value = {}
  purchaseLoading.value = false
  currentPurchase.value = {}
  sealLoading.value = false
  currentSeal.value = {}
  emit('close')
};
defineExpose({
@@ -495,4 +500,4 @@
   width: 200px;
   height: 60px;
}
</style>
</style>