OrderDetail.vue 9.27 KB
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ArrowLeft, VideoPlay, Download, Picture } from '@element-plus/icons-vue'
import type { OrderDetail } from '../types/order'
import { getMockOrderDetail } from '../mock/orderData'
import { ElMessage } from 'element-plus'

const route = useRoute()
const router = useRouter()
const loading = ref(false)
const orderDetail = ref<OrderDetail | null>(null)

// Image Preview State
const previewImageList = ref<string[]>([])
const currentVideoUrl = ref('')
const videoDialogVisible = ref(false)
const envImagesVisible = ref(false)
const envImageList = ref<string[]>([])

// Fetch Data
const fetchDetail = () => {
  loading.value = true
  // Mock API call
  setTimeout(() => {
    const id = route.params.id as string
    orderDetail.value = getMockOrderDetail(id)
    
    // Prepare images for preview
    if (orderDetail.value?.steps) {
      previewImageList.value = orderDetail.value.steps.map(s => s.imageUrl)
    }
    
    loading.value = false
  }, 500)
}

// Handlers
const handleBack = () => {
  router.back()
}

const showEnvImages = () => {
    // Show abnormal images (Mock: just pick images from steps that have abnormal flag, or all if none)
    if (orderDetail.value?.steps) {
        // Filter steps with abnormal or just take first 3 for demo
        const abnormalSteps = orderDetail.value.steps.filter(s => s.isAbnormal > 0)
        const sources = abnormalSteps.length > 0 ? abnormalSteps : orderDetail.value.steps.slice(0, 3)
        
        envImageList.value = sources.map(s => s.imageUrl)
        
        if (envImageList.value.length > 0) {
            envImagesVisible.value = true
        } else {
            ElMessage.warning('暂无异常图片')
        }
    }
}

const playVideo = (url: string) => {
  currentVideoUrl.value = url
  videoDialogVisible.value = true
}

const downloadVideo = (url: string) => {
    const link = document.createElement('a')
    link.href = url
    link.target = '_blank'
    link.download = 'video.mp4'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
}

const downloadAllVideos = () => {
    ElMessage.success('已开始批量下载所有视频')
}

const downloadScreenshots = () => {
    ElMessage.success('已开始下载质检截图')
}

onMounted(() => {
  fetchDetail()
})
</script>

<template>
  <div v-loading="loading" class="order-detail">
    <!-- Header -->
    <div class="flex items-center gap-4 mb-6">
      <el-button :icon="ArrowLeft" circle @click="handleBack" />
      <h2 class="text-xl font-bold">质检工单详情</h2>
    </div>

    <div v-if="orderDetail">
      <!-- 1. Basic Info -->
      <el-card shadow="never" class="mb-4">
        <template #header>
          <div class="font-bold">基础信息</div>
        </template>
        <el-descriptions :column="3" border>
          <el-descriptions-item label="Apply_id">{{ orderDetail.applyId }}</el-descriptions-item>
          <el-descriptions-item label="业务账号">{{ orderDetail.businessAccount }}</el-descriptions-item>
          <el-descriptions-item label="所属地市">{{ orderDetail.city }}</el-descriptions-item>
          
          <el-descriptions-item label="装机地址">{{ orderDetail.installAddress }}</el-descriptions-item>
          <el-descriptions-item label="师傅工号">{{ orderDetail.workerId }}</el-descriptions-item>
          <el-descriptions-item label="工单类型">{{ orderDetail.orderType }}</el-descriptions-item>
          
          <el-descriptions-item label="设备类型">{{ orderDetail.deviceType }}</el-descriptions-item>
          <el-descriptions-item label="工单ID">
            <template v-for="id in orderDetail.orderIds" :key="id">
              <div class="text-xs">{{ id }}</div>
            </template>
          </el-descriptions-item>
          <el-descriptions-item label="质检状态">
            <el-tag :type="orderDetail.status === '已完成' ? 'success' : ''">{{ orderDetail.status }}</el-tag>
          </el-descriptions-item>
          
          <el-descriptions-item label="无法质检原因">{{ orderDetail.cannotQcReason || '-' }}</el-descriptions-item>
          <el-descriptions-item label="开始时间">{{ orderDetail.startTime }}</el-descriptions-item>
          <el-descriptions-item label="完成时间">{{ orderDetail.completeTime || '-' }}</el-descriptions-item>
          
          <el-descriptions-item label="只能计数">
            <div class="flex gap-4">
              <span>不能拍: <span class="font-bold text-red-500">{{ orderDetail.noPhotoCount }}</span></span>
              <span>手动: <span class="font-bold text-orange-500">{{ orderDetail.manualInputCount }}</span></span>
            </div>
          </el-descriptions-item>
          <el-descriptions-item label="环境异常">
             <span class="font-bold text-red-500 mr-2">{{ orderDetail.envAbnormalCount }}</span>
             <el-button v-if="orderDetail.envAbnormalCount > 0" size="small" :icon="Picture" @click="showEnvImages">查看图片</el-button>
          </el-descriptions-item>
          <el-descriptions-item label="总耗时">{{ orderDetail.totalDuration }}</el-descriptions-item>
        </el-descriptions>
      </el-card>

      <!-- 2. QC Details -->
      <el-card shadow="never" class="mb-4">
         <template #header>
          <div class="font-bold">质检详情</div>
        </template>
        <el-table :data="orderDetail.steps" border style="width: 100%">
           <el-table-column type="index" label="序号" width="60" align="center" />
           <el-table-column prop="name" label="检测环节" />
           <el-table-column prop="duration" label="环节耗时" />
           <el-table-column prop="result" label="通过类型">
              <template #default="{ row }">
                 <el-tag type="success" v-if="row.result === '通过'">{{ row.result }}</el-tag>
                 <el-tag type="danger" v-else>{{ row.result }}</el-tag>
              </template>
           </el-table-column>
           <el-table-column label="查看图片">
              <template #default="{ row, $index }">
                  <el-image 
                    style="width: 50px; height: 50px"
                    :src="row.imageUrl" 
                    :zoom-rate="1.2"
                    :max-scale="7"
                    :min-scale="0.2"
                    :preview-src-list="previewImageList"
                    :initial-index="$index"
                    fit="cover"
                    preview-teleported
                    hide-on-click-modal
                  />
              </template>
           </el-table-column>
           <el-table-column prop="isAbnormal" label="是否异常">
               <template #default="{ row }">
                 <span :class="{'text-red-500 font-bold': row.isAbnormal > 0}">{{ row.isAbnormal }}</span>
               </template>
           </el-table-column>
        </el-table>
      </el-card>

      <!-- 3. Videos -->
      <el-card shadow="never" class="mb-4">
        <template #header>
          <div class="flex justify-between items-center">
            <span class="font-bold">质检视频</span>
            <div class="gap-2 flex">
               <el-button type="primary" :icon="Download" @click="downloadAllVideos">下载全部视频</el-button>
               <el-button type="success" :icon="Download" @click="downloadScreenshots">下载质检截图</el-button>
            </div>
          </div>
        </template>
        
        <div class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-4">
          <div v-for="video in orderDetail.videos" :key="video.id" class="border rounded-lg overflow-hidden relative group">
             <!-- Video Thumbnail -->
             <div class="aspect-video bg-black relative flex items-center justify-center cursor-pointer" @click="playVideo(video.videoUrl)">
               <img :src="video.thumbnailUrl" class="w-full h-full object-cover opacity-80 hover:opacity-100 transition" />
               <el-icon class="absolute text-white text-5xl opacity-80 group-hover:opacity-100 group-hover:scale-110 transition"><VideoPlay /></el-icon>
             </div>
             <!-- Video Footer -->
             <div class="p-2 bg-gray-50 flex justify-between items-center">
               <span class="text-sm truncate w-2/3" :title="video.name">{{ video.name }}</span>
               <el-button link type="primary" :icon="Download" @click="downloadVideo(video.videoUrl)">下载</el-button>
             </div>
          </div>
        </div>
        
        <div v-if="orderDetail.videos.length === 0" class="text-center text-gray-400 py-8">
           暂无视频
        </div>
      </el-card>
    </div>

    <!-- Video Player Dialog -->
    <el-dialog v-model="videoDialogVisible" title="视频播放" width="800px" destroy-on-close align-center>
        <video controls autoplay class="w-full max-h-[60vh] bg-black">
          <source :src="currentVideoUrl" type="video/mp4">
          您的浏览器不支持 Video 标签。
        </video>
    </el-dialog>

    <!-- Environment Images Dialog (Using Image Viewer) -->
    <el-image-viewer 
      v-if="envImagesVisible" 
      :url-list="envImageList" 
      @close="envImagesVisible = false"
    />
  </div>
</template>

<style scoped>
:deep(.el-descriptions__label) {
  font-weight: bold;
  background-color: #fafafa;
}
</style>