seatonwan9
2025-09-02 83d5b2be8fdf0ac0b59cacf6b344c8815ab4d040
src/views/tradeManage/detail/index.vue
@@ -24,7 +24,7 @@
          <el-tag :type="getStatusType(detail.status)" size="small">{{ detail.statusName }}</el-tag>
        </el-descriptions-item>
      </el-descriptions>
      <!-- 申请人信息(与订单信息同卡片,复用分隔标题样式) -->
      <el-descriptions
        :column="2"
@@ -74,7 +74,7 @@
          <div class="desc-wrap">{{ detail.productDesc }}</div>
        </el-descriptions-item>
      </el-descriptions>
      <!-- 订单详情(移动到交易内容下面,同一卡片内) -->
      <div ref="orderTableWrapRef">
        <el-table
@@ -228,7 +228,7 @@
    <!-- 审批追踪 -->
    <el-card class="mt15" shadow="never">
      <div class="title">审批追踪</div>
      <!-- 标签页 -->
      <!-- <el-tabs v-model="activeTab" class="approval-tabs">
        <el-tab-pane label="审批记录" name="records">
@@ -280,12 +280,12 @@
          </el-table>
        </el-tab-pane>
      </el-tabs> -->
      <!-- 外部系统审批轨迹 iframe -->
      <div class="iframe-wrap" v-if="workflowIframeUrl">
        <iframe :src="workflowIframeUrl" class="workflow-iframe" referrerpolicy="no-referrer"></iframe>
      </div>
    </el-card>
    <!-- 返回按钮 -->
    <div class="action-buttons">
@@ -302,6 +302,7 @@
import orderApi from '@/api/orderApi'
import createAxios from '@/utils/axios'
import productApi from '@/api/productApi'
import sysUserService from '@/api/sysUser'
import { useUserInfo } from '@/stores/modules/userInfo'
const hostUrl =  import.meta.env.VITE_AXIOS_BASE_URL
@@ -376,17 +377,17 @@
onMounted(async () => {
  const orderId = String(route.params.id || '')
  if (!orderId) return
  try {
    // 并行获取订单详情和协议类型检查
    const [orderRes, agreementRes] = await Promise.all([
      orderApi.getOrderDetail(orderId),
      orderApi.checkAgreementPriceType(orderId)
    ])
    const res = orderRes as any
    const data = res?.data || {}
    // 设置是否为协议订单
    const agreementResult = agreementRes as any
    isAgreementOrder.value = agreementResult?.data === true
@@ -411,8 +412,21 @@
    } catch (e) {
      // 忽略产品详情失败,不阻塞订单详情
    }
    // 获取用户信息
    try {
        const userRes: any = await sysUserService.getUserdetail({ userId: data.userId })
        if (userRes?.code === 200 && userRes.data) {
            // 用产品详情补全头信息
            data.unitName = userRes.data.unitName || data.unitName
            data.userName = userRes.data.name || data.userName
            data.userDept = userRes.data.departmentName || data.userDept
            data.userPhone = userRes.data.phone || data.userPhone
            data.userAccount = userRes.data.username || data.userAccount
        }
    }catch (e){
    }
    // 映射订单详情头部信息
    const head = {
@@ -479,11 +493,11 @@
        endDateObj.setFullYear(endDateObj.getFullYear() + item.period)
        endDate = endDateObj.toISOString().split('T')[0] // 格式化为 YYYY-MM-DD
      }
      return {
      return {
        name: item.name,
        start: data.applyTime ? data.applyTime.split('T')[0] : '', // 使用订单申请时间
        end: endDate,
        end: endDate,
        forever: item.period === 0, // 期限为0时设置为永久
        remark: item.remarks || '' // 使用套件信息中的remarks字段
      }
@@ -546,7 +560,7 @@
}
// 表头文字居中,但第一行的"详情"文字靠左对齐
const headerCenterStyle: CSSProperties = {
const headerCenterStyle: CSSProperties = {
  textAlign: 'center',
  fontSize: '14px',
  background: '#f3f6fb'
@@ -556,7 +570,7 @@
const bodyCellStyle: CSSProperties = { fontSize: '12px' }
// 审批追踪表格样式
const recordTableHeaderStyle: CSSProperties = {
const recordTableHeaderStyle: CSSProperties = {
  textAlign: 'center',
  fontSize: '14px',
  background: '#f3f6fb'
@@ -564,7 +578,7 @@
const recordTableCellStyle: CSSProperties = { fontSize: '12px' }
// 文件列表表格表头文字居中,但第一列的"交易文件"文字靠左对齐
const fileTableHeaderStyle: CSSProperties = {
const fileTableHeaderStyle: CSSProperties = {
  textAlign: 'center',
  fontSize: '14px',
  background: '#f3f6fb'
@@ -623,23 +637,23 @@
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
    'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
  ]
  // 如果MIME类型匹配,直接返回true
  if (previewableTypes.includes(file.type || '')) {
    return true
  }
  // 如果MIME类型为空或不匹配,根据文件扩展名判断
  const fileName = file.name || ''
  const fileExtension = fileName.toLowerCase().split('.').pop()
  const previewableExtensions = [
    'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp',
    'txt', 'html', 'htm', 'css', 'js',
    'pdf',
    'docx', 'xlsx', 'pptx'
  ]
  return previewableExtensions.includes(fileExtension)
}
@@ -655,13 +669,13 @@
    ElMessage.warning('文件链接不存在')
    return
  }
  // 获取文件扩展名
  const fileName = file.name || ''
  const fileExtension = fileName.toLowerCase().split('.').pop()
  let previewUrl = file.url
  // 如果文件存储在MinIO,优先使用预览URL
  if (file.url.includes('order-attachments')) {
    try {
@@ -673,9 +687,9 @@
          fileName: file.url
        }
      })
      console.log('预览URL响应:', previewResponse)
      // 检查响应格式
      const responseData = previewResponse as any
      if (responseData && responseData.code === 200 && responseData.data) {
@@ -693,7 +707,7 @@
            originalName: file.name
          }
        })
        // 创建预览URL
        const blob = new Blob([response as any])
        previewUrl = window.URL.createObjectURL(blob)
@@ -705,30 +719,30 @@
      return
    }
  }
  // 图片文件直接在新窗口打开
  if ((file.type && file.type.startsWith('image/')) ||
  if ((file.type && file.type.startsWith('image/')) ||
      ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension)) {
    console.log('预览图片文件:', previewUrl)
    window.open(previewUrl, '_blank')
    return
  }
  // PDF文件在新窗口打开
  if (file.type === 'application/pdf' || fileExtension === 'pdf') {
    console.log('预览PDF文件:', previewUrl)
    window.open(previewUrl, '_blank')
    return
  }
  // 文本文件在新窗口打开
  if ((file.type && file.type.startsWith('text/')) ||
  if ((file.type && file.type.startsWith('text/')) ||
      ['txt', 'html', 'htm', 'css', 'js'].includes(fileExtension)) {
    console.log('预览文本文件:', previewUrl)
    window.open(previewUrl, '_blank')
    return
  }
  // Office文档和其他文件类型,尝试在新窗口打开
  try {
    console.log('预览其他文件:', previewUrl)
@@ -745,14 +759,14 @@
    ElMessage.warning('文件链接不存在')
    return
  }
  console.log('开始下载文件:', file.name, 'URL:', file.url)
  try {
    // 如果文件存储在MinIO,使用后端直接下载API
    if (file.url.includes('order-attachments')) {
      console.log('使用MinIO下载API')
      // 使用axios通过代理访问后端API
      const response = await createAxios({
        url: `/admin/file/download`,
@@ -763,28 +777,28 @@
          originalName: file.name
        }
      })
      console.log('下载响应:', response)
      // 创建下载链接
      const blob = new Blob([response as any])
      const downloadUrl = window.URL.createObjectURL(blob)
      console.log('创建下载链接:', downloadUrl)
      const link = document.createElement('a')
      link.href = downloadUrl
      link.download = file.name || 'download'
      link.target = '_blank'
      link.rel = 'noopener noreferrer'
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      // 清理URL对象
      window.URL.revokeObjectURL(downloadUrl)
      ElMessage.success('文件下载成功')
    } else {
      console.log('使用直接URL下载')
@@ -794,11 +808,11 @@
      link.download = file.name || 'download'
      link.target = '_blank'
      link.rel = 'noopener noreferrer'
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      ElMessage.success('开始下载文件')
    }
  } catch (error) {
@@ -1052,7 +1066,7 @@
  gap: 8px;
  align-items: center;
  justify-content: center;
  .preview-btn {
    color: #409eff;
    &:hover {
@@ -1063,7 +1077,7 @@
      cursor: not-allowed;
    }
  }
  .download-btn {
    color: #67c23a;
    &:hover {