<template>
  <!-- 工作流详情滑块组件 -->
  <el-drawer
    v-model="visible"
    size="1200px"
    direction="rtl"
    :close-on-click-modal="true"
    :destroy-on-close="true"
    @closed="handleClose"
    class="workflow-detail-drawer"
  >
    <!-- 自定义头部：标题简洁明了 -->
    <template #header>
      <div class="ep-detail-header">
        <span>工作流详情</span>
      </div>
    </template>

    <!-- 加载态：骨架屏 -->
    <div v-if="detailLoading">
      <el-skeleton animated :rows="6" />
    </div>

    <!-- 错误态：结果面板 + 重试按钮 -->
    <el-result
      v-else-if="detailError"
      icon="warning"
      title="加载失败"
      :sub-title="detailError"
    >
      <template #extra>
        <el-button type="primary" @click="retryLoadDetail">重试</el-button>
      </template>
    </el-result>

    <!-- 详情内容 -->
    <div v-else-if="workflowDetail" class="ep-detail-body">
      <!-- 编辑模式 -->
      <div v-if="isEditing" class="edit-mode">
        <el-form :model="editForm" label-width="100px" label-position="left">
          <!-- 基本信息编辑 -->
          <el-row :gutter="20">
            <el-col :span="16">
              <el-form-item label="工作流名称" required>
                <el-input v-model="editForm.name" placeholder="请输入工作流名称" maxlength="128" show-word-limit />
              </el-form-item>
              
              <el-row :gutter="20">
                <el-col :span="12">
                  <el-form-item label="分类">
                    <el-select 
                      v-model="editForm.category" 
                      placeholder="请选择分类" 
                      style="width: 100%"
                      :loading="categoriesLoading"
                      :disabled="categoriesLoading"
                    >
                      <el-option 
                        v-for="category in workflowCategories" 
                        :key="category.value" 
                        :label="category.label" 
                        :value="category.value" 
                      />
                    </el-select>
                  </el-form-item>
                </el-col>
              </el-row>
            </el-col>
            
            <el-col :span="8">
              <el-form-item label="工作流封面">
                <div class="edit-cover-upload">
                  <div v-if="!editCoverFile && !editCoverPreviewUrl" class="cover-upload-placeholder" @click="triggerEditCoverSelect">
                    <p>点击上传新封面</p>
                    <p class="cover-hint">支持 JPG、PNG</p>
                  </div>
                  <div v-else class="cover-preview">
                    <img :src="editCoverPreviewUrl || editForm.coverUrl" alt="封面预览" class="cover-image" />
                    <div class="cover-actions">
                      <el-button @click="triggerEditCoverSelect" size="small">更换</el-button>
                      <el-button @click="clearEditCover" size="small" type="danger">删除</el-button>
                    </div>
                  </div>
                  <input ref="editCoverInput" type="file" accept="image/*" @change="handleEditCoverSelect" style="display: none" />
                </div>
              </el-form-item>
            </el-col>
          </el-row>
          
          <!-- 工作流数据编辑 -->
          <el-divider>工作流数据</el-divider>
          <div class="workflow-data-edit-section">
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="工作流逻辑">
                  <el-input 
                    v-model="editForm.data" 
                    type="textarea" 
                    :rows="8" 
                    placeholder="请输入工作流JSON数据"
                    class="workflow-data-textarea"
                  />
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="数据包文件">
                  <div class="data-file-upload">
                    <div v-if="!editDataFile" class="data-file-placeholder" @click="triggerEditDataSelect">
                      <div class="upload-icon">
                        <el-icon><Document /></el-icon>
                      </div>
                      <p>点击上传数据包</p>
                      <p class="upload-hint">支持 ZIP、RAR 等压缩文件，最大100MB</p>
                    </div>
                    <div v-else class="data-file-preview">
                      <div class="file-info">
                        <el-icon class="file-icon"><Document /></el-icon>
                        <p class="file-name">{{ editDataFile.name }}</p>
                      </div>
                      <div class="file-actions">
                        <el-button @click="triggerEditDataSelect" size="small" type="primary">更换</el-button>
                        <el-button @click="clearEditData" size="small" type="danger">删除</el-button>
                      </div>
                    </div>
                    <input ref="editDataInput" type="file" accept=".zip,.rar,.7z" @change="handleEditDataSelect" style="display: none" />
                  </div>
                </el-form-item>
              </el-col>
            </el-row>
          </div>
          
          <!-- 演示视频编辑 -->
          <el-divider>演示视频</el-divider>
          <div class="video-edit-section">
            <el-row :gutter="20">
              <el-col :span="24">
                <el-form-item label="视频文件">
                  <div class="video-file-upload">
                    <div v-if="!editVideoFile && !videoPreviewUrl" class="video-file-placeholder" @click="triggerEditVideoSelect" @drop="onEditVideoDrop" @dragover.prevent>
                      <div class="upload-icon">
                        <el-icon><VideoPlay /></el-icon>
                      </div>
                      <p>点击选择视频文件或拖拽文件到此处</p>
                      <p class="upload-hint">支持 MP4、AVI、MOV，大小不超过1GB</p>
                    </div>
                    <div v-else class="video-file-preview">
                      <div class="video-preview-container">
                        <video
                          v-if="videoPreviewUrl"
                          ref="editVideoPlayer"
                          :src="videoPreviewUrl"
                          controls
                          preload="metadata"
                          class="video-player"
                        >您的浏览器不支持视频播放</video>
                        <div class="video-overlay">
                          <p class="file-name" v-if="editVideoFile">{{ editVideoFile.name }}</p>
                          <div class="file-actions">
                            <el-button @click.stop="triggerEditVideoSelect" size="small" type="primary">更换</el-button>
                            <el-button @click.stop="clearEditVideo" size="small" type="danger">删除</el-button>
                          </div>
                        </div>
                      </div>
                    </div>
                    <input ref="editVideoInput" type="file" accept="video/*" @change="handleEditVideoSelect" style="display: none" />
                  </div>
                </el-form-item>
              </el-col>
            </el-row>
          </div>
          
          <!-- 工作流描述编辑 -->
          <el-divider>工作流描述</el-divider>
          <div class="description-editor-container">
            <QuillEditor 
              v-model:content="editForm.description" 
              content-type="html"
              placeholder="请输入工作流描述"
              :options="quillOptions"
              style="height: 400px;"
            />
          </div>
          
        </el-form>
      </div>
      
      <!-- 查看模式（原有内容） -->
      <div v-else class="view-mode">
        <!-- 顶部：封面 + 标题描述 -->
        <el-row :gutter="20">
          <el-col :span="8">
            <div class="cover-container">
              <el-image
                v-if="workflowDetail.coverUrl"
                :src="workflowDetail.coverUrl"
                fit="cover"
                class="ep-cover"
                :preview-src-list="[workflowDetail.coverUrl]"
                :hide-on-click-modal="true"
                :z-index="3000"
                :preview-teleported="true"
                lazy
              >
                <template #error>
                  <div class="cover-error">
                    <el-icon><Picture /></el-icon>
                    <span>加载失败</span>
                  </div>
                </template>
              </el-image>
              <div v-else class="no-cover">
                <el-icon><Picture /></el-icon>
                <span>暂无封面</span>
              </div>
            </div>
          </el-col>
          <el-col :span="16">
            <div class="workflow-info">
              <div class="ep-title">{{ workflowDetail.name || workflowDetail.title || '未命名工作流' }}</div>
              
              <!-- 工作流特有字段 -->
              <el-card shadow="never" class="ep-section info-card">
                <template #header>
                  <div class="ep-section-title">
                    <el-icon><InfoFilled /></el-icon>
                    工作流信息
                  </div>
                </template>
                <el-descriptions :column="2" border size="default">
                  <el-descriptions-item label="收藏数" v-if="workflowDetail.likeCount !== undefined">
                    <el-tag type="primary" effect="light">
                      <el-icon><Star /></el-icon>
                      {{ workflowDetail.likeCount || 0 }}
                    </el-tag>
                  </el-descriptions-item>
                  <el-descriptions-item label="评分" v-if="workflowDetail.rating">
                    <el-rate v-model="workflowDetail.rating" disabled show-score text-color="#ff9900" />
                  </el-descriptions-item>
                </el-descriptions>
              </el-card>
            </div>
          </el-col>
        </el-row>

        <!-- 基础元信息 -->
        <el-divider>基础信息</el-divider>
        <el-card shadow="never" class="ep-section meta-info-card">
          <el-descriptions :column="2" border size="default">
            <el-descriptions-item label="分类">
              <el-tag v-if="workflowDetail.category" type="info" effect="light">
                {{ workflowDetail.category }}
              </el-tag>
              <span v-else class="no-data">-</span>
            </el-descriptions-item>
            <el-descriptions-item label="审核状态">
              <el-tag :type="getAuditStatusType(detailAuditStatus)" effect="light">
                {{ formatAuditStatus(detailAuditStatus) }}
              </el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="拒绝原因" v-if="Number(detailAuditStatus) === 2 && detailRejectReason" :span="2">
              <div class="reject-reason-container">
                <el-icon class="reject-icon"><WarningFilled /></el-icon>
                <span class="reject-reason">{{ detailRejectReason }}</span>
              </div>
            </el-descriptions-item>
            <el-descriptions-item label="创建时间" v-if="workflowDetail.createTime">
              <el-tag type="info" effect="plain">
                <el-icon><Clock /></el-icon>
                {{ formatTime(workflowDetail.createTime) }}
              </el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="更新时间" v-if="workflowDetail.updateTime">
              <el-tag type="info" effect="plain">
                <el-icon><Refresh /></el-icon>
                {{ formatTime(workflowDetail.updateTime) }}
              </el-tag>
            </el-descriptions-item>
          </el-descriptions>
        </el-card>

        <!-- 工作流数据展示 -->
        <template v-if="workflowDetail.hasJsonData">
          <el-divider>工作流数据</el-divider>
          <el-card shadow="never" class="workflow-data-section data-card">
            <template #header>
              <div class="card-header">
                <div class="header-title">
                  <el-icon><Document /></el-icon>
                  <span>工作流配置数据</span>
                </div>
                <el-button type="primary" @click="copyJsonData" size="default">
                  <el-icon><CopyDocument /></el-icon>
                  复制数据
                </el-button>
              </div>
            </template>
            <div class="workflow-data-content">
              <div class="json-data-section">
                <div class="json-description">
                  <el-icon class="info-icon"><InfoFilled /></el-icon>
                  <span>工作流配置数据已准备就绪，点击复制按钮可将数据复制到剪贴板</span>
                </div>
              </div>
            </div>
          </el-card>
        </template>

        <!-- 视频演示 -->
        <template v-if="workflowDetail.vodVideoId">
          <el-divider>演示视频</el-divider>
          <el-card shadow="never" class="video-section video-card">
            <template #header>
              <div class="card-header">
                <div class="header-title">
                  <el-icon><VideoPlay /></el-icon>
                  <span>工作流演示视频</span>
                </div>
                <el-button type="primary" @click="playVideo" :loading="playerLoading" size="default">
                  <el-icon v-if="!playerLoading"><CaretRight /></el-icon>
                  {{ playerLoading ? '加载中...' : '播放演示' }}
                </el-button>
              </div>
            </template>
            
            <!-- 播放器卡片 -->
            <div v-if="player || playerLoading || playerError" class="player-card">
              <div class="player-header">
                <div class="player-title">
                  <el-icon><VideoPlay /></el-icon>
                  正在播放：{{ workflowDetail.name || '工作流演示' }}
                </div>
                <el-button @click="closePlayer" size="small" type="info" plain>
                  <el-icon><Close /></el-icon>
                  关闭播放
                </el-button>
              </div>
              <div class="player-body">
                <div v-if="playerError" class="player-error">
                  <el-icon><WarningFilled /></el-icon>
                  {{ playerError }}
                </div>
                <div v-else-if="playerLoading" class="player-loading">
                  <el-icon class="loading-icon"><Loading /></el-icon>
                  播放器加载中...
                </div>
                <div v-show="!playerLoading && !playerError" :id="playerDomId" class="prism-player"></div>
              </div>
            </div>
          </el-card>
        </template>

        <!-- 作品图集 -->
        <template v-if="detailGalleryImages.length">
          <el-divider>作品图集</el-divider>
          <el-card shadow="never" class="gallery-section gallery-card">
            <template #header>
              <div class="card-header">
                <div class="header-title">
                  <el-icon><Picture /></el-icon>
                  <span>作品图集</span>
                </div>
                <el-tag type="info" effect="light">
                  共 {{ detailGalleryImages.length }} 张图片
                </el-tag>
              </div>
            </template>
            <div class="gallery-display">
              <div class="gallery-display-grid">
                <div v-for="(imageUrl, index) in detailGalleryImages" :key="index" class="gallery-display-item">
                  <el-image
                    :src="imageUrl"
                    :alt="`图集图片 ${index + 1}`"
                    fit="cover"
                    class="gallery-display-image"
                    :preview-src-list="detailGalleryImages"
                    :initial-index="index"
                    :hide-on-click-modal="true"
                    :z-index="3000"
                    :preview-teleported="true"
                    lazy
                  >
                    <template #error>
                      <div class="gallery-error">
                        <el-icon><Picture /></el-icon>
                        <span>加载失败</span>
                      </div>
                    </template>
                  </el-image>
                </div>
              </div>
            </div>
          </el-card>
        </template>

        <!-- 数据文件下载 -->
        <template v-if="workflowDetail.hasDataFile">
          <el-divider>相关资源</el-divider>
          <el-card shadow="never" class="resource-section resource-card">
            <template #header>
              <div class="card-header">
                <div class="header-title">
                  <el-icon><FolderOpened /></el-icon>
                  <span>相关资源</span>
                </div>
              </div>
            </template>
            <div class="resource-item">
              <div class="resource-info">
                <div class="resource-icon-wrapper">
                  <el-icon class="resource-icon"><Document /></el-icon>
                </div>
                <div class="resource-details">
                  <span class="resource-text">工作流数据文件</span>
                  <span class="resource-desc">包含完整的工作流配置和相关资源</span>
                </div>
              </div>
              <el-button type="primary" @click="downloadDataFile" size="default">
                <el-icon><Download /></el-icon>
                下载文件
              </el-button>
            </div>
          </el-card>
        </template>
        
        <!-- 工作流描述 -->
        <template v-if="workflowDetail.description">
          <el-divider>工作流描述</el-divider>
          <el-card shadow="never" class="ep-section description-card">
            <div class="ep-desc rich-text-content" v-html="formatRichTextContent(workflowDetail.description)"></div>
          </el-card>
        </template>
      </div>
    </div>

    <!-- 底部操作按钮 -->
    <div class="drawer-footer">
      <el-button @click="visible = false">关闭</el-button>
      <template v-if="isEditing">
        <el-button @click="cancelEdit">取消</el-button>
        <el-button type="primary" :loading="editUploading" @click="saveEdit">保存修改</el-button>
      </template>
      <el-button v-else type="primary" @click="startEdit">修改工作流</el-button>
    </div>

    <!-- 视频上传进度显示 -->
    <div v-if="isUploadingVideo" class="video-upload-progress">
      <div class="progress-header">
        <h4><el-icon><VideoPlay /></el-icon> 正在上传视频到VOD</h4>
        <div class="upload-status">{{ uploadStatus || '视频上传中...' }}</div>
      </div>
      
      <div class="progress-info">
        <div class="progress-main">
          <span class="progress-text">{{ videoUploadProgress }}%</span>
          <span class="progress-speed">{{ videoUploadSpeed }}</span>
        </div>
        <div class="progress-time">
          <span>已用时: {{ formatDuration(videoUploadTimeElapsed) }}</span>
          <span v-if="videoUploadTimeRemaining > 0">预计剩余: {{ formatDuration(videoUploadTimeRemaining) }}</span>
        </div>
      </div>
      
      <el-progress 
        :percentage="videoUploadProgress" 
        :stroke-width="8"
        :show-text="false"
        :color="getProgressColor(videoUploadProgress)"
        class="progress-bar"
      />
      
      <div class="progress-details">
        <div class="file-info">
          <span>{{ formatFileSize(videoUploadedBytes || 0) }} / {{ formatFileSize(editVideoFile?.size || 0) }}</span>
          <span class="file-name">{{ editVideoFile?.name }}</span>
        </div>
      </div>
    </div>

    <!-- 全屏上传遮罩层 -->
    <div v-if="editUploading && (isUploadingVideo || editVideoFile)" class="upload-overlay">
      <div class="overlay-content">
        <h3>正在保存工作流修改，请稍候</h3>
        <p v-if="isUploadingVideo">视频正在上传中，请不要关闭或离开此页面。</p>
        <p v-else>文件正在处理中...</p>
        <div class="overlay-progress">
          <el-progress 
            :percentage="isUploadingVideo ? videoUploadProgress : 50" 
            :stroke-width="10" 
            :show-text="true" 
            :color="getProgressColor(isUploadingVideo ? videoUploadProgress : 50)" 
          />
        </div>
        <div class="overlay-stats" v-if="isUploadingVideo">
          <span>{{ videoUploadSpeed }}</span>
          <span>{{ formatDuration(videoUploadTimeElapsed) }}</span>
        </div>
      </div>
    </div>
  </el-drawer>
</template>

<script setup>
import { ref, reactive, computed, watch, nextTick, onUnmounted } from 'vue'
import { getWorkflowDetail, updateWorkflow, getWorkflowCategories } from '@/api/workflow.js'
import { getPlayAuth, createUploadAuth, refreshUploadAuth } from '@/api/vod.js'
import { getPostSignature } from '@/api/files.js'
import Aliplayer from 'aliyun-aliplayer'
import 'aliyun-aliplayer/build/skins/default/aliplayer-min.css'
import { getPlayerConfig, getLicenseConfig } from '@/config/aliplayer.js'
import { ElMessage } from 'element-plus'
import { 
  Document, Download, VideoPlay, Delete, Picture, Edit, CopyDocument,
  InfoFilled, Star, WarningFilled, Clock, Refresh, CaretRight, 
  Close, Loading, FolderOpened
} from '@element-plus/icons-vue'
import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'

// Props
const props = defineProps({
  modelValue: {
    type: Boolean,
    default: false
  },
  workflowId: {
    type: String,
    default: ''
  },
  listItem: {
    type: Object,
    default: () => ({})
  },
  // 新增props：JSON数据和数据包URL
  jsonData: {
    type: String,
    default: ''
  },
  dataFileUrl: {
    type: String,
    default: ''
  }
})

// Emits
const emit = defineEmits(['update:modelValue', 'refresh'])

// Quill编辑器配置 - 使用默认图片处理，保存时统一上传到OSS
const quillOptions = {
  theme: 'snow',
  modules: {
    toolbar: [
      ['bold', 'italic', 'underline', 'strike'],
      ['blockquote', 'code-block'],
      [{ 'header': 1 }, { 'header': 2 }],
      [{ 'list': 'ordered'}, { 'list': 'bullet' }],
      [{ 'script': 'sub'}, { 'script': 'super' }],
      [{ 'indent': '-1'}, { 'indent': '+1' }],
      [{ 'direction': 'rtl' }],
      [{ 'size': ['small', false, 'large', 'huge'] }],
      [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
      [{ 'color': [] }, { 'background': [] }],
      [{ 'font': [] }],
      [{ 'align': [] }],
      ['clean'],
      ['link', 'image']
    ]
  }
}

// 弹窗显示状态
const visible = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value)
})

// 详情相关状态
const workflowDetail = ref(null)
const detailLoading = ref(false)
const detailError = ref('')

// 处理富文本内容中的base64图片上传到OSS
const processDescriptionImages = async (description) => {
  if (!description) return description
  
  const base64Regex = /<img[^>]+src="data:image\/([^;]+);base64,([^"]+)"[^>]*>/g
  let processedDescription = description
  const uploadPromises = []
  
  let match
  while ((match = base64Regex.exec(description)) !== null) {
    const [fullMatch, imageType, base64Data] = match
    
    // 将base64转换为File对象
    const byteCharacters = atob(base64Data)
    const byteNumbers = new Array(byteCharacters.length)
    for (let i = 0; i < byteCharacters.length; i++) {
      byteNumbers[i] = byteCharacters.charCodeAt(i)
    }
    const byteArray = new Uint8Array(byteNumbers)
    const blob = new Blob([byteArray], { type: `image/${imageType}` })
    const file = new File([blob], `description_image_${Date.now()}.${imageType}`, { type: `image/${imageType}` })
    
    // 创建上传Promise
    const uploadPromise = getPostSignature(file).then(uploadRes => {
      const ossUrl = uploadRes.url || uploadRes.data?.url || uploadRes
      // 替换原来的base64图片为OSS链接
      processedDescription = processedDescription.replace(fullMatch, fullMatch.replace(`data:image/${imageType};base64,${base64Data}`, ossUrl))
    }).catch(error => {
      console.warn('富文本图片上传失败:', error)
      // 如果上传失败，保留原始的base64图片
    })
    
    uploadPromises.push(uploadPromise)
  }
  
  // 等待所有图片上传完成
  await Promise.all(uploadPromises)
  return processedDescription
}

// 编辑状态
const isEditing = ref(false)
const editForm = reactive({
  name: '',
  description: '',
  coverUrl: '',
  category: '',
  data: '',
  dataFileUrl: '',
  detailGallery: ''
})

// 编辑时的文件状态
const editCoverFile = ref(null)
const editCoverPreviewUrl = ref('')
const editDataFile = ref(null)
const editVideoFile = ref(null)
const editVideoPlayer = ref(null)
const videoPreviewUrl = ref('')
const editUploading = ref(false)
const editCoverInput = ref(null)
const editDataInput = ref(null)
const editVideoInput = ref(null)


// 视频上传进度状态
const videoUploadProgress = ref(0)
const videoUploadSpeed = ref('0 KB/s')
const videoUploadTimeElapsed = ref(0)
const videoUploadTimeRemaining = ref(0)
const videoUploadedBytes = ref(0)
const videoUploadStartTime = ref(0)
const videoLastUploadedBytes = ref(0)
const isUploadingVideo = ref(false)
const uploadStatus = ref('')

// 播放器相关状态
const player = ref(null)
const playerLoading = ref(false)
const playerError = ref('')
const playerDomId = 'J_workflowPlayer'

// 分类数据状态
const workflowCategories = ref([])
const categoriesLoading = ref(false)

// 统一审核信息：详情缺失时回退到列表项
const detailAuditStatus = computed(() => {
  const a = workflowDetail.value?.auditStatus
  return (a !== undefined && a !== null) ? a : props.listItem?.auditStatus
})
const detailRejectReason = computed(() => {
  return workflowDetail.value?.rejectReason ?? props.listItem?.rejectReason ?? ''
})
const detailReviewTime = computed(() => {
  return workflowDetail.value?.reviewTime ?? props.listItem?.reviewTime ?? ''
})

// 解析图集数据
const detailGalleryImages = computed(() => {
  if (!workflowDetail.value?.detailGallery) return []
  try {
    const gallery = JSON.parse(workflowDetail.value.detailGallery)
    return Array.isArray(gallery) ? gallery : []
  } catch (e) {
    console.warn('解析图集数据失败:', e)
    return []
  }
})


// 检测数据是否有变更
const hasDataChanged = () => {
  if (!workflowDetail.value) return false
  
  const original = workflowDetail.value
  
  // 检查基本信息
  if (editForm.name !== (original.name || original.title || '')) return true
  if (editForm.description !== (original.description || '')) return true
  if (editForm.category !== (original.category || '')) return true
  if (editForm.data !== (original.data || '')) return true
  
  // 检查是否有新的封面文件
  if (editCoverFile.value) return true
  
  // 检查是否有新的数据文件
  if (editDataFile.value) return true
  
  // 检查是否有新的视频文件
  if (editVideoFile.value) return true
  
  
  return false
}

// 移除formatWorkflowData计算属性，直接使用原始数据

const formatAuditStatus = (val) => {
  if (val === 0 || val === '0') return '待审核'
  if (val === 1 || val === '1') return '已通过'
  if (val === 2 || val === '2') return '未通过'
  return '未知'
}

// 获取审核状态对应的标签类型
const getAuditStatusType = (val) => {
  if (val === 0 || val === '0') return 'warning'
  if (val === 1 || val === '1') return 'success'
  if (val === 2 || val === '2') return 'danger'
  return 'info'
}

const formatTime = (timeStr) => {
  if (!timeStr) return '-'
  try {
    const date = new Date(timeStr)
    return date.toLocaleString('zh-CN')
  } catch (e) {
    return timeStr
  }
}

// 格式化富文本内容
const formatRichTextContent = (content) => {
  if (!content) return ''
  
  let formattedContent = content.toString()
  
  // 处理换行符 - 将 \n 转换为 <br>
  formattedContent = formattedContent.replace(/\n/g, '<br>')
  
  // 处理多个连续空格
  formattedContent = formattedContent.replace(/ {2,}/g, (match) => {
    return '&nbsp;'.repeat(match.length)
  })
  
  // 处理制表符
  formattedContent = formattedContent.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;')
  
  // 确保HTML标签正常工作，不需要额外转义
  return formattedContent
}

// 监听弹窗显示状态
watch(visible, async (newVal) => {
  if (newVal && props.workflowId) {
    await loadWorkflowDetail(props.workflowId)
  }
})

// 加载工作流分类
const loadWorkflowCategories = async () => {
  if (workflowCategories.value.length > 0) {
    // 如果已经有数据，则不重复请求
    return
  }
  
  try {
    categoriesLoading.value = true
    const response = await getWorkflowCategories()
    
    // 统一解包，兼容不同的响应格式
    const categoriesData = response?.data || response || []
    
    // 如果后端返回的是对象数组，转换为选项格式
    if (Array.isArray(categoriesData)) {
      workflowCategories.value = categoriesData.map(item => {
        if (typeof item === 'string') {
          return { label: item, value: item }
        } else if (item && typeof item === 'object') {
          return {
            label: item.label || item.name || item.categoryName || item.category || item.value,
            value: item.value || item.name || item.categoryName || item.category || item.label
          }
        }
        return { label: '其他', value: '其他' }
      })
    } else {
      // 如果接口返回格式异常，使用默认分类
      console.warn('工作流分类数据格式异常，使用默认分类:', categoriesData)
      workflowCategories.value = [
        { label: '人工智能', value: '人工智能' },
        { label: '数据分析', value: '数据分析' },
        { label: '图像处理', value: '图像处理' },
        { label: '文本生成', value: '文本生成' },
        { label: '音频处理', value: '音频处理' },
        { label: '代码生成', value: '代码生成' },
        { label: '其他', value: '其他' }
      ]
    }
    
    console.log('[WorkflowDetailModal] 加载工作流分类成功:', workflowCategories.value)
  } catch (e) {
    console.error('获取工作流分类失败:', e)
    // 使用默认分类作为后备
    workflowCategories.value = [
      { label: '人工智能', value: '人工智能' },
      { label: '数据分析', value: '数据分析' },
      { label: '图像处理', value: '图像处理' },
      { label: '文本生成', value: '文本生成' },
      { label: '音频处理', value: '音频处理' },
      { label: '代码生成', value: '代码生成' },
      { label: '其他', value: '其他' }
    ]
    ElMessage.warning('获取分类数据失败，使用默认分类')
  } finally {
    categoriesLoading.value = false
  }
}

// 加载工作流详情
const loadWorkflowDetail = async (id) => {
  detailLoading.value = true
  detailError.value = ''
  workflowDetail.value = null
  // 清理播放器状态
  disposePlayer()
  
  try {
    const detailData = await getWorkflowDetail(id)
    
    if (detailData) {
      // 统一解包，兼容 { code, message, data } 与直接对象两种返回
      const responseData = detailData?.data ?? detailData
      
      // 判断是否为新的分页格式数据（包含 records 数组）
      if (responseData?.records && Array.isArray(responseData.records)) {
        // 新格式：从 records 数组中找到对应 ID 的工作流
        console.log('[WorkflowDetailModal] 检测到分页格式数据，从 records 中查找 ID:', id)
        const targetWorkflow = responseData.records.find(item => 
          item?.id?.toString() === id?.toString()
        )
        
        if (targetWorkflow) {
          workflowDetail.value = targetWorkflow
          console.log('[WorkflowDetailModal] 找到目标工作流:', targetWorkflow)
        } else {
          console.warn('[WorkflowDetailModal] 在 records 中未找到 ID 为', id, '的工作流')
          // 如果找不到指定ID，但records不为空，使用第一条数据
          if (responseData.records.length > 0) {
            workflowDetail.value = responseData.records[0]
            console.log('[WorkflowDetailModal] 使用第一条工作流数据:', responseData.records[0])
          } else {
            detailError.value = '未找到对应的工作流数据'
          }
        }
      } else {
        // 旧格式：直接使用原有逻辑
        console.log('[WorkflowDetailModal] 使用旧格式数据解析')
        // 如果返回的数据包含workflow字段，则提取workflow数据
        workflowDetail.value = responseData?.workflow ?? responseData
      }
    } else {
      detailError.value = '未找到工作流详情信息'
    }
  } catch (e) {
    console.error('获取工作流详情失败', e)
    detailError.value = '获取工作流详情失败，请稍后重试'
  } finally {
    detailLoading.value = false
  }
}

const retryLoadDetail = () => {
  if (props.workflowId) {
    loadWorkflowDetail(props.workflowId)
  }
}

// 弹窗关闭处理
const handleClose = () => {
  workflowDetail.value = null
  detailError.value = ''
  isEditing.value = false
  clearEditState()
  disposePlayer()
}

// 清理编辑状态
const clearEditState = () => {
  editForm.name = ''
  editForm.description = ''
  editForm.coverUrl = ''
  editForm.category = ''
  editForm.data = ''
  editForm.dataFileUrl = ''
  
  editCoverFile.value = null
  if (editCoverPreviewUrl.value) {
    try { URL.revokeObjectURL(editCoverPreviewUrl.value) } catch (e) {}
  }
  editCoverPreviewUrl.value = ''
  editDataFile.value = null
  editVideoFile.value = null
  if (videoPreviewUrl.value) {
    try { URL.revokeObjectURL(videoPreviewUrl.value) } catch (e) {}
  }
  videoPreviewUrl.value = ''
  
  
  // 重置视频上传进度状态
  videoUploadProgress.value = 0
  videoUploadSpeed.value = '0 KB/s'
  videoUploadTimeElapsed.value = 0
  videoUploadTimeRemaining.value = 0
  videoUploadedBytes.value = 0
  videoUploadStartTime.value = 0
  videoLastUploadedBytes.value = 0
  isUploadingVideo.value = false
  uploadStatus.value = ''
}

// 开始编辑
const startEdit = async () => {
  if (!workflowDetail.value) return
  
  // 加载分类数据（如果还没有加载）
  await loadWorkflowCategories()
  
  // 初始化编辑表单
  editForm.name = workflowDetail.value.name || workflowDetail.value.title || ''
  editForm.description = workflowDetail.value.description || ''
  editForm.coverUrl = workflowDetail.value.coverUrl || ''
  editForm.category = workflowDetail.value.category || ''
  editForm.data = props.jsonData || ''
  editForm.dataFileUrl = props.dataFileUrl || ''
  
  isEditing.value = true
}

// 取消编辑
const cancelEdit = () => {
  clearEditState()
  isEditing.value = false
}

// 封面上传相关
const triggerEditCoverSelect = () => {
  editCoverInput.value?.click()
}

const handleEditCoverSelect = (event) => {
  const file = event.target.files?.[0]
  if (!file) return
  
  if (!file.type.startsWith('image/')) {
    ElMessage.error('请选择有效的图片文件')
    return
  }
  
  if (file.size > 5 * 1024 * 1024) {
    ElMessage.error('图片文件大小不能超过5MB')
    return
  }
  
  if (editCoverPreviewUrl.value) {
    try { URL.revokeObjectURL(editCoverPreviewUrl.value) } catch (e) {}
  }
  
  editCoverFile.value = file
  editCoverPreviewUrl.value = URL.createObjectURL(file)
}

const clearEditCover = () => {
  if (editCoverPreviewUrl.value) {
    try { URL.revokeObjectURL(editCoverPreviewUrl.value) } catch (e) {}
  }
  editCoverFile.value = null
  editCoverPreviewUrl.value = ''
  if (editCoverInput.value) {
    editCoverInput.value.value = ''
  }
}

// 数据包文件上传
const triggerEditDataSelect = () => {
  editDataInput.value?.click()
}

const handleEditDataSelect = (event) => {
  const file = event.target.files?.[0]
  if (!file) return
  
  if (file.size > 100 * 1024 * 1024) {
    ElMessage.error('数据包文件大小不能超过100MB')
    return
  }
  
  editDataFile.value = file
}

const clearEditData = () => {
  editDataFile.value = null
  if (editDataInput.value) {
    editDataInput.value.value = ''
  }
}

// 视频文件上传
const triggerEditVideoSelect = () => {
  editVideoInput.value?.click()
}

const handleEditVideoSelect = (event) => {
  const file = event.target.files?.[0]
  if (!file) return
  
  console.log('选择的视频文件:', file.name, file.type, file.size)
  
  if (!file.type.startsWith('video/')) {
    ElMessage.error('请选择有效的视频文件')
    return
  }
  
  if (file.size > 1024 * 1024 * 1024) {
    ElMessage.error('视频文件大小不能超过1GB')
    return
  }
  
  if (videoPreviewUrl.value) {
    try { URL.revokeObjectURL(videoPreviewUrl.value) } catch (e) {}
  }
  editVideoFile.value = file
  videoPreviewUrl.value = URL.createObjectURL(file)
  
  console.log('视频预览URL:', videoPreviewUrl.value)
  console.log('editVideoFile.value:', editVideoFile.value)
  
  ElMessage.success(`视频文件选择成功：${file.name}`)
}

const onEditVideoDrop = (event) => {
  event.preventDefault()
  const files = event.dataTransfer.files
  if (files && files.length > 0) {
    const file = files[0]
    console.log('拖拽的视频文件:', file.name, file.type, file.size)
    
    if (!file.type.startsWith('video/')) {
      ElMessage.error('请选择有效的视频文件')
      return
    }
    if (file.size > 1024 * 1024 * 1024) {
      ElMessage.error('视频文件大小不能超过1GB')
      return
    }
    if (videoPreviewUrl.value) {
      try { URL.revokeObjectURL(videoPreviewUrl.value) } catch (e) {}
    }
    editVideoFile.value = file
    videoPreviewUrl.value = URL.createObjectURL(file)
    
    console.log('拖拽视频预览URL:', videoPreviewUrl.value)
    ElMessage.success(`视频文件拖拽成功：${file.name}`)
  }
}

const clearEditVideo = () => {
  editVideoFile.value = null
  if (videoPreviewUrl.value) {
    try { URL.revokeObjectURL(videoPreviewUrl.value) } catch (e) {}
  }
  videoPreviewUrl.value = ''
  if (editVideoInput.value) {
    editVideoInput.value.value = ''
  }
}


// 保存编辑
const saveEdit = async () => {
  try {
    // 基础验证
    if (!editForm.name.trim()) {
      ElMessage.error('请填写工作流名称')
      return
    }

    // 检查数据是否有变更
    if (!hasDataChanged()) {
      ElMessage.info('数据未发生变更，无需保存')
      return
    }

    editUploading.value = true
    
    // 处理富文本描述中的base64图片上传到OSS
  
    const processedDescription = await processDescriptionImages(editForm.description)
    editForm.description = processedDescription
    
    // 上传封面到OSS（参考WorkflowUploadComponent逻辑，使用POST签名）
    let coverUrl = null
    let shouldUpdateCover = false
    if (editCoverFile.value) {
      try {
        coverUrl = await uploadToOssWithPostSignature(editCoverFile.value, 'workflow-cover')
        shouldUpdateCover = true
        console.log('[WorkflowDetailModal] 封面上传成功:', coverUrl)
      } catch (e) {
        console.warn('封面上传失败:', e)
        ElMessage.warning('封面上传失败，将使用原有封面')
        // 保持原有封面
        coverUrl = editForm.coverUrl
        shouldUpdateCover = !!coverUrl // 只有原本有封面时才更新
      }
    } else if (editForm.coverUrl) {
      // 没有选择新封面，但原本有封面，保持原有封面
      coverUrl = editForm.coverUrl
      shouldUpdateCover = true
    }

    // 上传数据包文件到OSS
    let dataFileUrl = null
    let shouldUpdateDataFile = false
    if (editDataFile.value) {
      try {
        dataFileUrl = await uploadToOssWithPostSignature(editDataFile.value, 'workflow-data')
        shouldUpdateDataFile = true
        console.log('[WorkflowDetailModal] 数据文件上传成功:', dataFileUrl)
      } catch (e) {
        console.warn('数据包上传失败:', e)
        ElMessage.warning('数据包上传失败，将使用原有文件')
        // 保持原有数据文件
        dataFileUrl = editForm.dataFileUrl
        shouldUpdateDataFile = !!dataFileUrl // 只有原本有数据文件时才更新
      }
    } else if (editForm.dataFileUrl) {
      // 没有选择新数据文件，但原本有数据文件，保持原有数据文件
      dataFileUrl = editForm.dataFileUrl
      shouldUpdateDataFile = true
    }

    // 构建更新数据
    const updateData = {
      name: editForm.name.trim(),
      description: editForm.description.trim(),
      category: editForm.category
    }
    
    // 只有在 data 字段有内容时才添加
    if (editForm.data && editForm.data.trim()) {
      updateData.data = editForm.data.trim()
    }

    // 只有在需要更新封面时才添加 coverUrl 字段
    if (shouldUpdateCover && coverUrl && coverUrl.trim()) {
      updateData.coverUrl = coverUrl
    }
    
    // 只有在需要更新数据文件时才添加 dataFileUrl 字段
    if (shouldUpdateDataFile && dataFileUrl && dataFileUrl.trim()) {
      updateData.dataFileUrl = dataFileUrl
    }

    // 如果选择了新视频，上传到VOD并设置 vodVideoId / videoId
    if (editVideoFile.value) {
      try {
        isUploadingVideo.value = true
        uploadStatus.value = '正在上传视频到VOD...'
        const vodResult = await uploadVideoToVod(editVideoFile.value)
        if (vodResult?.videoId) {
          updateData.vodVideoId = vodResult.videoId
          updateData.videoId = vodResult.videoId
          console.log('[WorkflowDetailModal] 视频上传成功，videoId:', vodResult.videoId)
        } else {
          console.warn('[WorkflowDetailModal] 视频上传返回的结果无效:', vodResult)
          ElMessage.warning('视频上传完成，但未获取到有效的视频ID')
        }
        uploadStatus.value = '视频上传完成'
      } catch (e) {
        console.error('[WorkflowDetailModal] 视频上传失败:', e)
        ElMessage.warning('视频上传失败，将使用原有视频')
      } finally {
        isUploadingVideo.value = false
      }
    }


    // 调用更新接口
    console.log('[WorkflowDetailModal] 准备更新工作流:', {
      workflowId: props.workflowId,
      updateData,
      hasNewCover: !!editCoverFile.value,
      hasNewData: !!editDataFile.value,
      hasNewVideo: !!editVideoFile.value,
      shouldUpdateCover,
      shouldUpdateDataFile,
      finalCoverUrl: coverUrl,
      finalDataFileUrl: dataFileUrl
    })
    
    await updateWorkflow(props.workflowId, updateData)
    console.log('[WorkflowDetailModal] 工作流更新成功')
    ElMessage.success('工作流更新成功')
    
    // 重新加载详情
    await loadWorkflowDetail(props.workflowId)
    
    // 退出编辑模式
    isEditing.value = false
    clearEditState()
    
    // 通知父组件刷新列表
    emit('refresh')

  } catch (e) {
    console.error('保存失败:', e)
    ElMessage.error(e.message || '保存失败，请稍后重试')
  } finally {
    editUploading.value = false
  }
}

// 使用POST签名上传文件到COS（与上传组件保持一致）
const uploadToOssWithPostSignature = async (file, dirHint = '') => {
  // 获取签名
  const postSignatureResult = await getPostSignature({ fileName: file.name, userId: '' })
  if (postSignatureResult.code !== 200) {
    throw new Error(postSignatureResult.message || '获取上传签名失败')
  }
  const signatureData = postSignatureResult.data
  const rawFile = file
  const objectKey = signatureData.dir + Date.now() + '_' + rawFile.name

  const formData = new FormData()
  // COS POST 表单上传必需字段
  formData.append('key', objectKey)
  formData.append('policy', signatureData.policy)
  formData.append('q-sign-algorithm', signatureData['q-sign-algorithm'])
  formData.append('q-ak', signatureData['q-ak'])
  formData.append('q-key-time', signatureData['q-key-time'])
  formData.append('q-signature', signatureData['q-signature'])
  formData.append('file', rawFile)

  const uploadResponse = await fetch(signatureData.host, { method: 'POST', body: formData })
  if (!uploadResponse.ok) {
    throw new Error(`上传失败: HTTP ${uploadResponse.status}`)
  }
  return `${signatureData.host}/${objectKey}`
}

// 上传视频到VOD（参考上传组件）
const uploadVideoToVod = async (file) => {
  return new Promise((resolve, reject) => {
    try {
      // 检查文件是否有效
      if (!file || !file.name || !file.size) {
        console.error('[WorkflowDetailModal] 无效的视频文件:', file)
        return reject(new Error('无效的视频文件'))
      }
      
      console.log('[WorkflowDetailModal] 开始上传视频:', {
        fileName: file.name,
        fileSize: formatFileSize(file.size),
        fileType: file.type
      })
      
      // 检查SDK是否加载
      if (typeof window.AliyunUpload === 'undefined' || typeof window.AliyunUpload.Vod !== 'function') {
        console.error('[WorkflowDetailModal] 阿里云上传SDK未加载')
        return reject(new Error('阿里云上传SDK未加载'))
      }

      // 初始化进度状态
      videoUploadProgress.value = 0
      videoUploadSpeed.value = '0 KB/s'
      videoUploadTimeElapsed.value = 0
      videoUploadTimeRemaining.value = 0
      videoUploadedBytes.value = 0
      videoUploadStartTime.value = Date.now()
      videoLastUploadedBytes.value = 0

      // 获取当前登录用户ID（如果有）
      const currentUser = JSON.parse(localStorage.getItem('user') || '{}')
      const userId = currentUser.id || ''
      
      console.log('[WorkflowDetailModal] 初始化VOD上传器，userId:', userId)
      
      const uploader = new window.AliyunUpload.Vod({
        userId: userId.toString(), // 确保是字符串类型
        region: 'cn-shanghai',
        partSize: 1024 * 1024,
        parallel: 5,
        retryCount: 3,
        retryDuration: 2,
        onUploadstarted: async (uploadInfo) => {
          try {
            const authResult = await createUploadAuth({
              userId: userId.toString(), // 使用同样的 userId
              title: editForm.name || '工作流预览视频',
              description: editForm.description || '',
              tags: '',
              cateId: '',
              coverUrl: editForm.coverUrl || '',
              fileName: file.name,
              fileSize: file.size
            })
            // 检查返回结果是否完整
            if (!authResult || !authResult.uploadAuth || !authResult.uploadAddress || !authResult.videoId) {
              console.error('[WorkflowDetailModal] 获取上传凭证失败，返回数据不完整:', authResult)
              throw new Error('获取上传凭证失败，返回数据不完整')
            }
            
            const { uploadAuth, uploadAddress, videoId } = authResult
            console.log('[WorkflowDetailModal] 成功获取上传凭证，videoId:', videoId)
            
            // 设置上传凭证
            uploader.setUploadAuthAndAddress(uploadInfo, uploadAuth, uploadAddress, videoId)
          } catch (err) {
            reject(err)
          }
        },
        onUploadProgress: (uploadInfo, totalSize, progress) => {
          // 更新上传进度
          if (typeof progress === 'number' && progress >= 0 && progress <= 1) {
            videoUploadProgress.value = Math.round(progress * 100)
            videoUploadedBytes.value = Math.round(progress * totalSize)
            
            // 更新上传速度和时间
            updateVideoUploadSpeed()
            updateVideoUploadTime()
          }
        },
        onUploadSucceed: (uploadInfo) => {
          videoUploadProgress.value = 100
          videoUploadedBytes.value = file.size
          videoUploadTimeElapsed.value = Math.floor((Date.now() - videoUploadStartTime.value) / 1000)
          videoUploadTimeRemaining.value = 0
          resolve({ videoId: uploadInfo.videoId, success: true })
        },
        onUploadFailed: (_uploadInfo, _code, message) => {
          reject(new Error(message || '视频上传失败'))
        },
        onUploadTokenExpired: async (uploadInfo) => {
          try {
            console.log('[WorkflowDetailModal] 上传凭证过期，刷新凭证，videoId:', uploadInfo.videoId)
            const refreshResult = await refreshUploadAuth({
              videoId: uploadInfo.videoId,
              userId: userId.toString() // 添加 userId 参数
            })
            
            // 检查刷新结果
            if (!refreshResult || !refreshResult.uploadAuth) {
              console.error('[WorkflowDetailModal] 刷新上传凭证失败:', refreshResult)
              throw new Error('刷新上传凭证失败')
            }
            
            // 正确提取 uploadAuth
            const uploadAuth = refreshResult.uploadAuth
            console.log('[WorkflowDetailModal] 成功刷新上传凭证')
            
            // 设置新的上传凭证
            uploader.setUploadAuthAndAddress(uploadInfo, uploadAuth, uploadInfo.uploadAddress, uploadInfo.videoId)
          } catch (error) {
            console.error('[WorkflowDetailModal] 刷新上传凭证出错:', error)
            reject(error)
          }
        }
      })

      uploader.addFile(file, null, null, null, null)
      uploader.startUpload()
    } catch (e) {
      reject(e)
    }
  })
}

// 更新视频上传速度
const updateVideoUploadSpeed = () => {
  const now = Date.now()
  const timeDiff = (now - videoUploadStartTime.value) / 1000
  const bytesDiff = videoUploadedBytes.value - videoLastUploadedBytes.value
  
  if (timeDiff > 0) {
    const speed = bytesDiff / timeDiff
    videoUploadSpeed.value = formatFileSize(speed) + '/s'
  }
  
  videoLastUploadedBytes.value = videoUploadedBytes.value
}

// 更新视频上传时间
const updateVideoUploadTime = () => {
  videoUploadTimeElapsed.value = Math.floor((Date.now() - videoUploadStartTime.value) / 1000)
  
  if (videoUploadProgress.value > 0) {
    const totalTime = videoUploadTimeElapsed.value / (videoUploadProgress.value / 100)
    videoUploadTimeRemaining.value = Math.max(0, Math.floor(totalTime - videoUploadTimeElapsed.value))
  }
}

// 格式化持续时间（秒数）
const formatDuration = (seconds) => {
  if (seconds < 60) {
    return `${seconds}秒`
  } else if (seconds < 3600) {
    const minutes = Math.floor(seconds / 60)
    const remainingSeconds = seconds % 60
    return `${minutes}分${remainingSeconds}秒`
  } else {
    const hours = Math.floor(seconds / 3600)
    const minutes = Math.floor((seconds % 3600) / 60)
    const remainingSeconds = seconds % 60
    return `${hours}小时${minutes}分${remainingSeconds}秒`
  }
}

// 格式化文件大小
const formatFileSize = (bytes) => {
  if (!bytes || bytes === 0 || isNaN(bytes) || !isFinite(bytes)) {
    return '0 B'
  }
  
  const numBytes = Number(bytes)
  if (isNaN(numBytes) || !isFinite(numBytes)) {
    return '0 B'
  }
  
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(numBytes) / Math.log(k))
  
  if (i < 0 || i >= sizes.length) {
    return '0 B'
  }
  
  return parseFloat((numBytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

// 获取进度条颜色
const getProgressColor = (progress) => {
  if (progress < 30) return '#f56c6c'
  if (progress < 70) return '#e6a23c'
  return '#67c23a'
}

// 播放视频
const playVideo = async () => {
  if (!workflowDetail.value?.vodVideoId) return
  
  try {
    playerLoading.value = true
    playerError.value = ''
    disposePlayer()

    // 获取播放凭证
    const authRes = await getPlayAuth({ videoId: workflowDetail.value.vodVideoId })
    const playAuth = authRes?.playAuth || authRes?.PlayAuth || authRes
    if (!playAuth) {
      throw new Error('未获取到播放凭证')
    }

    // 等待DOM更新
    await nextTick()

    // 初始化播放器
    const baseConfig = getPlayerConfig({
      id: playerDomId,
      vid: workflowDetail.value.vodVideoId,
      playauth: playAuth
    })
    const license = getLicenseConfig()
    player.value = new Aliplayer(
      { ...baseConfig, license },
      () => { console.log('Workflow player created') }
    )
  } catch (err) {
    console.error('初始化播放器失败:', err)
    playerError.value = err?.message || '播放器初始化失败'
  } finally {
    playerLoading.value = false
  }
}

const disposePlayer = () => {
  try {
    if (player.value && typeof player.value.dispose === 'function') {
      player.value.dispose()
    }
  } catch (_) {}
  player.value = null
}

const closePlayer = () => {
  disposePlayer()
  playerError.value = ''
  playerLoading.value = false
}

// 下载数据文件
const downloadDataFile = () => {
  if (props.dataFileUrl) {
    const link = document.createElement('a')
    link.href = props.dataFileUrl
    link.download = `workflow_${workflowDetail.value?.id || props.workflowId}_data.zip`
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    ElMessage.success('开始下载工作流数据文件')
  } else {
    ElMessage.warning('未找到数据包下载链接')
  }
}

// 复制数据
const copyJsonData = async () => {
  // 直接复制原始的data字段值，不进行任何格式化
  const rawData = props.jsonData
  
  if (!rawData) {
    ElMessage.warning('暂无数据可复制')
    return
  }
  
  try {
    await navigator.clipboard.writeText(rawData)
    ElMessage.success('数据已复制到剪贴板')
  } catch (e) {
    // 如果剪贴板API不可用，使用备用方法
    const textArea = document.createElement('textarea')
    textArea.value = rawData
    document.body.appendChild(textArea)
    textArea.select()
    try {
      document.execCommand('copy')
      ElMessage.success('数据已复制到剪贴板')
    } catch (err) {
      console.error('复制失败:', err)
      ElMessage.error('复制失败，请手动复制')
    }
    document.body.removeChild(textArea)
  }
}

// 组件销毁时清理资源
onUnmounted(() => {
  // 清理预览URL
  galleryPreviewUrls.value.forEach(url => {
    try { URL.revokeObjectURL(url) } catch (e) {}
  })
  replacementPreviewUrls.value.forEach(url => {
    try { URL.revokeObjectURL(url) } catch (e) {}
  })
  
  // 清理播放器
  disposePlayer()
  
  // 清理其他预览URL
  if (editCoverPreviewUrl.value) {
    try { URL.revokeObjectURL(editCoverPreviewUrl.value) } catch (e) {}
  }
  if (videoPreviewUrl.value) {
    try { URL.revokeObjectURL(videoPreviewUrl.value) } catch (e) {}
  }
})
</script>

<style scoped>
/* 工作流详情滑块样式 */
:deep(.workflow-detail-drawer .el-drawer__header) {
  padding: 16px 24px;
  border-bottom: 1px solid #ebeef5;
  margin-bottom: 0;
}

:deep(.workflow-detail-drawer .el-drawer__body) {
  padding: 0;
  height: calc(100vh - 120px);
  overflow-y: auto;
}

/* 详情内容区域 */
.ep-detail-header {
  text-align: left;
  font-size: 18px;
  font-weight: 600;
  color: #333;
}

.ep-detail-body {
  text-align: left;
  padding: 20px 24px;
  height: calc(100vh - 180px);
  overflow-y: auto;
  padding-bottom: 20px;
}

/* 底部操作按钮样式 */
.drawer-footer {
  position: sticky;
  bottom: 0;
  background: #fff;
  padding: 16px 24px;
  border-top: 1px solid #ebeef5;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
  z-index: 10;
}

/* 编辑模式样式 */
.edit-mode {
  max-height: calc(100vh - 220px);
  overflow-y: auto;
  padding-bottom: 20px;
}

/* 工作流数据编辑区域 */
.workflow-data-edit-section {
  margin: 20px 0;
  padding: 20px;
  background: #fafbfc;
  border-radius: 8px;
  border: 1px solid #e4e7ed;
}

.workflow-data-textarea :deep(.el-textarea__inner) {
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 13px;
  line-height: 1.5;
  background: #f8f9fa;
}

/* 视频编辑区域 */
.video-edit-section {
  margin: 20px 0;
  padding: 20px;
  background: #fafbfc;
  border-radius: 8px;
  border: 1px solid #e4e7ed;
}


/* 富文本编辑器容器 - 完全脱离表单系统 */
.description-editor-container {
  width: 100%;
  margin: 20px 0;
  padding: 0;
  box-sizing: border-box;
}

.description-editor-container .vue-quill-editor {
  width: 100%;
  margin: 0;
  padding: 0;
}

.edit-cover-upload {
  width: 100%;
  height: 200px;
  border: 2px dashed #d9d9d9;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  transition: border-color 0.3s ease;
  cursor: pointer;
}

.edit-cover-upload:hover {
  border-color: #409eff;
}

.cover-upload-placeholder {
  text-align: center;
  color: #999;
}

.cover-preview {
  position: relative;
  width: 100%;
  height: 100%;
}

.cover-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 6px;
}

.cover-actions {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  gap: 4px;
}

.cover-hint {
  font-size: 12px;
  color: #999;
  margin-top: 4px;
}

/* 文件上传区域 */
.data-file-upload {
  width: 100%;
  min-height: 140px;
  border: 2px dashed #d9d9d9;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
  cursor: pointer;
  position: relative;
  background: #fafbfc;
}

.data-file-placeholder {
  text-align: center;
  color: #666;
  padding: 20px;
}

.upload-icon {
  font-size: 32px;
  color: #409eff;
  margin-bottom: 12px;
}

.data-file-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 20px;
}

.file-info {
  display: flex;
  align-items: center;
  gap: 8px;
}

.file-icon {
  font-size: 24px;
  color: #409eff;
}

.video-file-upload {
  width: 100%;
  min-height: 240px;
  border: 2px dashed #d9d9d9;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  background: #fafbfc;
}

.video-file-placeholder {
  text-align: center;
  color: #666;
  padding: 20px;
}

.video-preview-container {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 6px;
  overflow: hidden;
}

.video-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.8));
  color: white;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.data-file-upload:hover {
  border-color: #409eff;
  background: #f0f9ff;
}

.video-file-upload:hover {
  border-color: #409eff;
  background: #f0f9ff;
}

/* 视频预览样式 */
.video-file-preview {
  width: 100%;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 10px;
}

.video-player {
  width: 100%;
  max-width: 100%;
  height: auto;
  max-height: 300px;
  border-radius: 6px;
  background: #000;
  object-fit: contain;
}

.file-name {
  font-size: 14px;
  color: #333;
  text-align: center;
  word-break: break-all;
  margin: 0;
}

.data-file-placeholder,
.video-file-placeholder {
  text-align: center;
  color: #999;
}

.data-file-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.data-file-preview .file-name {
  font-size: 14px;
  color: #333;
  text-align: center;
  word-break: break-all;
  margin: 0;
}

.file-actions {
  display: flex;
  gap: 8px;
}

.upload-hint {
  font-size: 12px;
  color: #999;
  margin-top: 4px;
}

/* 编辑操作按钮 */
.edit-actions {
  margin-top: 24px;
  padding-top: 16px;
  border-top: 1px solid #ebeef5;
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

/* 查看模式样式 */
.view-mode {
  padding-bottom: 20px;
}

/* 封面容器 */
.cover-container {
  width: 100%;
  height: 240px;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.cover-container:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

.ep-cover {
  width: 100%;
  height: 100%;
  border-radius: 12px;
}

.no-cover {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  color: #666;
  font-size: 16px;
  gap: 8px;
}

.no-cover .el-icon {
  font-size: 48px;
  color: #999;
}

/* 封面加载错误样式 */
.cover-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #999;
  background: #f5f7fa;
}

.cover-error .el-icon {
  font-size: 48px;
  margin-bottom: 8px;
  color: #c0c4cc;
}

.cover-error span {
  font-size: 14px;
  color: #909399;
}

/* 工作流信息区域 */
.workflow-info {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.ep-title {
  font-size: 28px;
  font-weight: 700;
  margin-bottom: 16px;
  color: #1a1a1a;
  line-height: 1.3;
  word-break: break-word;
}

.ep-desc {
  font-size: 16px;
  color: #666;
  line-height: 1.8;
  margin-bottom: 20px;
}

/* 富文本内容样式 */
.rich-text-content {
  word-break: break-word;
  word-wrap: break-word;
  overflow-wrap: break-word;
  white-space: pre-wrap; /* 保留换行和空格 */
}

.rich-text-content :deep(h1),
.rich-text-content :deep(h2),
.rich-text-content :deep(h3),
.rich-text-content :deep(h4),
.rich-text-content :deep(h5),
.rich-text-content :deep(h6) {
  margin: 16px 0 8px 0 !important;
  font-weight: 600 !important;
  color: #333 !important;
  line-height: 1.4 !important;
}

.rich-text-content h1 { font-size: 24px; }
.rich-text-content h2 { font-size: 20px; }
.rich-text-content h3 { font-size: 18px; }
.rich-text-content h4 { font-size: 16px; }
.rich-text-content h5 { font-size: 14px; }
.rich-text-content h6 { font-size: 12px; }

.rich-text-content :deep(p) {
  margin: 8px 0 !important;
  line-height: 1.6 !important;
  color: #666 !important;
  /* 不强制设置 text-align，保留原有的对齐样式 */
}

.rich-text-content :deep(div) {
  margin: 4px 0 !important;
  line-height: 1.6 !important;
  color: #666 !important;
  /* 不强制设置 text-align，保留原有的对齐样式 */
}

.rich-text-content :deep(span) {
  line-height: 1.6 !important;
  color: #666 !important;
  /* 不强制设置 text-align，保留原有的对齐样式 */
}

.rich-text-content strong,
.rich-text-content b {
  font-weight: 600;
  color: #333;
}

.rich-text-content em,
.rich-text-content i {
  font-style: italic;
  color: #666;
}

.rich-text-content u {
  text-decoration: underline;
}

.rich-text-content s,
.rich-text-content del {
  text-decoration: line-through;
  color: #999;
}

.rich-text-content mark {
  background-color: #fff3cd;
  padding: 2px 4px;
  border-radius: 2px;
}

.rich-text-content ul,
.rich-text-content ol {
  margin: 8px 0;
  padding-left: 20px;
}

.rich-text-content li {
  margin: 4px 0;
  line-height: 1.5;
  color: #666;
}

.rich-text-content dl {
  margin: 8px 0;
}

.rich-text-content dt {
  font-weight: 600;
  color: #333;
  margin: 8px 0 4px 0;
}

.rich-text-content dd {
  margin: 0 0 8px 20px;
  color: #666;
}

.rich-text-content blockquote {
  margin: 12px 0;
  padding: 8px 16px;
  border-left: 4px solid #409eff;
  background-color: #f8f9fa;
  color: #666;
  font-style: italic;
}

.rich-text-content code {
  background-color: #f5f5f5;
  padding: 2px 6px;
  border-radius: 4px;
  font-family: 'Courier New', 'Monaco', 'Menlo', monospace;
  font-size: 14px;
  color: #e96900;
}

.rich-text-content pre {
  background-color: #f5f5f5;
  padding: 12px;
  border-radius: 6px;
  overflow-x: auto;
  margin: 12px 0;
  font-family: 'Courier New', 'Monaco', 'Menlo', monospace;
  font-size: 13px;
  line-height: 1.4;
}

.rich-text-content pre code {
  background: none;
  padding: 0;
  color: #333;
  font-size: inherit;
}

.rich-text-content a {
  color: #409eff;
  text-decoration: none;
  transition: color 0.2s ease;
}

.rich-text-content a:hover {
  color: #337ecc;
  text-decoration: underline;
}

.rich-text-content :deep(img) {
  height: 460px !important;
  width: auto !important;
  max-width: 100% !important;
  border-radius: 6px !important;
  margin: 8px 0 !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
  display: block !important;
  object-fit: contain !important;
}

.rich-text-content video {
  max-width: 100%;
  height: auto;
  border-radius: 6px;
  margin: 8px 0;
}

.rich-text-content table {
  width: 100%;
  border-collapse: collapse;
  margin: 12px 0;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  border-radius: 6px;
  overflow: hidden;
}

.rich-text-content table th,
.rich-text-content table td {
  border: 1px solid #e0e0e0;
  padding: 8px 12px;
  text-align: left;
  vertical-align: top;
}

.rich-text-content table th {
  background-color: #f8f9fa;
  font-weight: 600;
  color: #333;
}

.rich-text-content table tr:nth-child(even) {
  background-color: #f9f9f9;
}

.rich-text-content table tr:hover {
  background-color: #f0f8ff;
}

.rich-text-content hr {
  border: none;
  border-top: 1px solid #eee;
  margin: 16px 0;
}

.rich-text-content sub {
  font-size: 0.8em;
  vertical-align: sub;
}

.rich-text-content sup {
  font-size: 0.8em;
  vertical-align: super;
}

.rich-text-content small {
  font-size: 0.9em;
  color: #999;
}

/* 文本颜色样式 */
.rich-text-content :deep(.text-red) { color: #f56c6c !important; }
.rich-text-content :deep(.text-orange) { color: #e6a23c !important; }
.rich-text-content :deep(.text-yellow) { color: #f7ba2a !important; }
.rich-text-content :deep(.text-green) { color: #67c23a !important; }
.rich-text-content :deep(.text-blue) { color: #409eff !important; }
.rich-text-content :deep(.text-purple) { color: #9c27b0 !important; }
.rich-text-content :deep(.text-gray) { color: #909399 !important; }

/* 文本大小样式 */
.rich-text-content :deep(.text-xs) { font-size: 12px !important; }
.rich-text-content :deep(.text-sm) { font-size: 14px !important; }
.rich-text-content :deep(.text-base) { font-size: 16px !important; }
.rich-text-content :deep(.text-lg) { font-size: 18px !important; }
.rich-text-content :deep(.text-xl) { font-size: 20px !important; }
.rich-text-content :deep(.text-2xl) { font-size: 24px !important; }

/* 文本对齐样式 */
.rich-text-content :deep(.text-left) { text-align: left !important; }
.rich-text-content :deep(.text-center) { text-align: center !important; }
.rich-text-content :deep(.text-right) { text-align: right !important; }
.rich-text-content :deep(.text-justify) { text-align: justify !important; }

/* 支持行内样式的对齐 */
.rich-text-content :deep(p[style*="text-align: left"]),
.rich-text-content :deep(div[style*="text-align: left"]),
.rich-text-content :deep(span[style*="text-align: left"]) {
  text-align: left !important;
}

.rich-text-content :deep(p[style*="text-align: center"]),
.rich-text-content :deep(div[style*="text-align: center"]),
.rich-text-content :deep(span[style*="text-align: center"]) {
  text-align: center !important;
}

.rich-text-content :deep(p[style*="text-align: right"]),
.rich-text-content :deep(div[style*="text-align: right"]),
.rich-text-content :deep(span[style*="text-align: right"]) {
  text-align: right !important;
}

.rich-text-content :deep(p[style*="text-align: justify"]),
.rich-text-content :deep(div[style*="text-align: justify"]),
.rich-text-content :deep(span[style*="text-align: justify"]) {
  text-align: justify !important;
}

/* Quill编辑器的对齐类 */
.rich-text-content :deep(.ql-align-left) {
  text-align: left !important;
}

.rich-text-content :deep(.ql-align-center) {
  text-align: center !important;
}

.rich-text-content :deep(.ql-align-right) {
  text-align: right !important;
}

.rich-text-content :deep(.ql-align-justify) {
  text-align: justify !important;
}

/* 背景色样式 */
.rich-text-content :deep(.bg-highlight) { background-color: #fff3cd !important; padding: 2px 4px; border-radius: 2px; }
.rich-text-content :deep(.bg-info) { background-color: #d1ecf1 !important; padding: 2px 4px; border-radius: 2px; }
.rich-text-content :deep(.bg-success) { background-color: #d4edda !important; padding: 2px 4px; border-radius: 2px; }
.rich-text-content :deep(.bg-warning) { background-color: #fff3cd !important; padding: 2px 4px; border-radius: 2px; }
.rich-text-content :deep(.bg-danger) { background-color: #f8d7da !important; padding: 2px 4px; border-radius: 2px; }

/* 特殊样式框 */
.rich-text-content :deep(.callout) {
  padding: 12px 16px !important;
  margin: 12px 0 !important;
  border-radius: 6px !important;
  border-left: 4px solid #409eff !important;
}

.rich-text-content :deep(.callout.info) {
  background-color: #f0f9ff !important;
  border-color: #409eff !important;
  color: #0369a1 !important;
}

.rich-text-content :deep(.callout.success) {
  background-color: #f0fdf4 !important;
  border-color: #67c23a !important;
  color: #166534 !important;
}

.rich-text-content :deep(.callout.warning) {
  background-color: #fffbeb !important;
  border-color: #e6a23c !important;
  color: #92400e !important;
}

.rich-text-content :deep(.callout.danger) {
  background-color: #fef2f2 !important;
  border-color: #f56c6c !important;
  color: #dc2626 !important;
}

/* Quill编辑器样式 */
.ql-editor {
  min-height: 150px !important;
  line-height: 1.6 !important;
}

.ql-container.ql-snow {
  border: 1px solid #dcdfe6 !important;
  border-radius: 4px !important;
}

.ql-toolbar.ql-snow {
  border: 1px solid #dcdfe6 !important;
  border-bottom: none !important;
  border-radius: 4px 4px 0 0 !important;
}

/* 黑白ins风格按钮样式 */
.el-button {
  border-radius: 6px !important;
  font-weight: 500 !important;
  transition: all 0.3s ease !important;
  border: 1.5px solid !important;
}

/* 主要按钮 - 黑色风格 */
.el-button--primary {
  background-color: #000000 !important;
  border-color: #000000 !important;
  color: #ffffff !important;
}

.el-button--primary:hover {
  background-color: #333333 !important;
  border-color: #333333 !important;
  color: #ffffff !important;
}

.el-button--primary:active {
  background-color: #000000 !important;
  border-color: #000000 !important;
}

/* 默认按钮 - 白色风格 */
.el-button--default {
  background-color: #ffffff !important;
  border-color: #000000 !important;
  color: #000000 !important;
}

.el-button--default:hover {
  background-color: #f5f5f5 !important;
  border-color: #000000 !important;
  color: #000000 !important;
}

/* 危险按钮 - 深色风格 */
.el-button--danger {
  background-color: #2d2d2d !important;
  border-color: #2d2d2d !important;
  color: #ffffff !important;
}

.el-button--danger:hover {
  background-color: #1a1a1a !important;
  border-color: #1a1a1a !important;
  color: #ffffff !important;
}

/* 警告按钮 - 灰色风格 */
.el-button--warning {
  background-color: #666666 !important;
  border-color: #666666 !important;
  color: #ffffff !important;
}

.el-button--warning:hover {
  background-color: #4d4d4d !important;
  border-color: #4d4d4d !important;
  color: #ffffff !important;
}

/* 成功按钮 - 深灰色风格 */
.el-button--success {
  background-color: #333333 !important;
  border-color: #333333 !important;
  color: #ffffff !important;
}

.el-button--success:hover {
  background-color: #1a1a1a !important;
  border-color: #1a1a1a !important;
  color: #ffffff !important;
}

/* 信息按钮 - 浅灰色风格 */
.el-button--info {
  background-color: #f0f0f0 !important;
  border-color: #999999 !important;
  color: #333333 !important;
}

.el-button--info:hover {
  background-color: #e0e0e0 !important;
  border-color: #666666 !important;
  color: #000000 !important;
}

/* 小按钮 */
.el-button--small {
  padding: 6px 12px !important;
  font-size: 12px !important;
}

/* 加载状态 */
.el-button.is-loading {
  opacity: 0.7 !important;
}

/* 禁用状态 */
.el-button.is-disabled {
  background-color: #f5f5f5 !important;
  border-color: #d9d9d9 !important;
  color: #b3b3b3 !important;
}

.el-button.is-disabled:hover {
  background-color: #f5f5f5 !important;
  border-color: #d9d9d9 !important;
  color: #b3b3b3 !important;
}

/* 文本按钮 */
.el-button--text {
  background-color: transparent !important;
  border-color: transparent !important;
  color: #000000 !important;
}

.el-button--text:hover {
  background-color: #f5f5f5 !important;
  color: #000000 !important;
}

/* 链接按钮 */
.el-button.is-link {
  color: #000000 !important;
  text-decoration: underline !important;
}

.el-button.is-link:hover {
  color: #333333 !important;
}

.ep-section {
  margin-bottom: 20px;
}

.ep-section-title {
  font-weight: 600;
  color: #333;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 16px;
}

.ep-section-title .el-icon {
  color: #409eff;
  font-size: 18px;
}

/* 卡片样式 */
.info-card,
.description-card,
.meta-info-card,
.data-card,
.video-card,
.gallery-card,
.resource-card {
  border: 1px solid #e4e7ed;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
  transition: all 0.3s ease;
}

.info-card:hover,
.description-card:hover,
.meta-info-card:hover,
.data-card:hover,
.video-card:hover,
.gallery-card:hover,
.resource-card:hover {
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
}

/* 卡片头部 */
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0;
}

.header-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: #333;
  font-size: 16px;
}

.header-title .el-icon {
  color: #409eff;
  font-size: 18px;
}

/* 无数据显示 */
.no-data {
  color: #c0c4cc;
  font-style: italic;
}

/* 拒绝原因容器 */
.reject-reason-container {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 12px;
  background: #fef2f2;
  border-radius: 8px;
  border: 1px solid #fecaca;
}

.reject-icon {
  color: #f56c6c;
  font-size: 16px;
  margin-top: 2px;
  flex-shrink: 0;
}

.like-count {
  color: #409eff;
  font-weight: 500;
}

/* 加载动画 */
.loading-icon {
  animation: rotate 2s linear infinite;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

/* 工作流数据样式 */
.workflow-data-section {
  margin-bottom: 16px;
}

.workflow-data-content {
  padding: 16px 0;
}

.json-data-section {
  padding: 20px;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  background: #fafbfc;
}

.json-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.json-title {
  font-size: 16px;
  font-weight: 600;
  color: #333;
}

.json-description {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #666;
  font-size: 14px;
  line-height: 1.5;
}

.json-description .el-icon {
  color: #409eff;
  font-size: 16px;
}

/* 视频播放器样式 */
.video-section {
  margin-bottom: 20px;
}

/* 播放器卡片样式（与课程弹窗一致） */
.player-card {
  margin-top: 20px;
  border: 1px solid #e4e7ed;
  border-radius: 12px;
  overflow: hidden;
  background: #fff;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}

.player-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  border-bottom: 1px solid #e4e7ed;
}

.player-title {
  font-weight: 600;
  color: #333;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 16px;
}

.player-title .el-icon {
  color: #409eff;
  font-size: 18px;
}

.player-body {
  padding: 16px;
}

.player-loading, .player-error {
  text-align: center;
  color: #666;
  padding: 40px 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  font-size: 16px;
}

.player-error {
  color: #f56c6c;
}

.player-error .el-icon {
  font-size: 24px;
  color: #f56c6c;
}

.prism-player {
  width: 100%;
  height: 360px;
  border-radius: 8px;
  overflow: hidden;
}

/* 资源下载样式 */
.resource-section {
  margin-bottom: 20px;
}

.resource-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px;
  background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  border-radius: 12px;
  border: 1px solid #e4e7ed;
  transition: all 0.3s ease;
}

.resource-item:hover {
  background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.resource-info {
  display: flex;
  align-items: center;
  gap: 16px;
}

.resource-icon-wrapper {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: linear-gradient(135deg, #409eff 0%, #1890ff 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
}

.resource-icon {
  font-size: 24px;
  color: #fff;
}

.resource-details {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.resource-text {
  font-weight: 600;
  color: #333;
  font-size: 16px;
}

.resource-desc {
  font-size: 14px;
  color: #666;
  line-height: 1.4;
}

/* 视频上传进度条样式 */
.video-upload-progress {
  margin-top: 20px;
  padding: 20px;
  background: #f8f9fa;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  border: 1px solid #ebeef5;
}

.video-upload-progress .progress-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px solid #ebeef5;
}

.video-upload-progress .progress-header h4 {
  margin: 0;
  color: #333;
  font-size: 18px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 8px;
}

.video-upload-progress .progress-header .el-icon {
  font-size: 20px;
  color: #409eff;
}

.video-upload-progress .upload-status {
  font-size: 14px;
  color: #666;
  font-weight: 500;
}

.video-upload-progress .progress-info {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  font-size: 14px;
  color: #666;
}

.video-upload-progress .progress-main {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.video-upload-progress .progress-text {
  font-weight: 600;
  color: #409eff;
  font-size: 16px;
}

.video-upload-progress .progress-speed {
  font-size: 14px;
  color: #909399;
}

.video-upload-progress .progress-time {
  font-size: 14px;
  color: #909399;
}

.video-upload-progress .progress-details {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 15px;
  padding-top: 10px;
  border-top: 1px solid #ebeef5;
}

.video-upload-progress .file-info {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.video-upload-progress .file-name {
  font-size: 14px;
  color: #333;
  font-weight: 500;
}

/* 全屏上传遮罩层 */
.upload-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.75);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.overlay-content {
  width: min(560px, 90%);
  background: rgba(20, 20, 20, 0.9);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 10px 40px rgba(0,0,0,0.5);
  border-radius: 16px;
  padding: 28px 24px;
  color: #fff;
  text-align: center;
}

.overlay-content h3 {
  margin: 6px 0 10px;
  font-size: 20px;
  font-weight: 700;
  color: #fff;
}

.overlay-content p {
  margin: 0 0 14px;
  color: #ddd;
  line-height: 1.6;
}

.overlay-progress {
  margin: 14px 0;
}

.overlay-stats {
  margin-top: 6px;
  color: #cfd8dc;
  font-size: 13px;
  display: flex;
  justify-content: space-between;
}


/* 图集展示样式 */
.gallery-section {
  margin-bottom: 16px;
}

.gallery-display {
  padding: 16px 0;
}

.gallery-count {
  font-weight: 500;
  color: #333;
  margin-bottom: 16px;
  padding-left: 4px;
}

.gallery-display-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 16px;
}

.gallery-display-item {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.gallery-display-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}

.gallery-display-image {
  width: 100%;
  height: 100%;
  border-radius: 8px;
}

.gallery-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #999;
  background: #f5f7fa;
}

.gallery-error .el-icon {
  font-size: 24px;
  margin-bottom: 8px;
}

/* 拒绝原因样式 */
.reject-reason {
  color: #f56c6c;
  font-weight: 500;
  word-break: break-all;
  line-height: 1.5;
}

/* 图片预览器简化样式 */
:deep(.el-image-viewer__wrapper) {
  z-index: 3000 !important;
}

/* 隐藏预览器中的部分功能按钮，保持简洁 */
:deep(.el-image-viewer__actions) {
  background: rgba(0, 0, 0, 0.5) !important;
  padding: 8px !important;
  border-radius: 6px !important;
}

/* 保留基本的导航和关闭按钮，隐藏其他功能 */
:deep(.el-image-viewer__actions .el-image-viewer__actions__inner) {
  display: flex !important;
  justify-content: center !important;
  gap: 8px !important;
}

/* 隐藏不常用的功能按钮 */
:deep(.el-image-viewer__actions .el-image-viewer__actions__inner > :not(:first-child):not(:nth-child(2)):not(:last-child)) {
  display: none !important;
}

/* 简化切换按钮样式 */
:deep(.el-image-viewer__btn) {
  background: rgba(0, 0, 0, 0.5) !important;
  border: none !important;
  border-radius: 50% !important;
  width: 40px !important;
  height: 40px !important;
  font-size: 18px !important;
}

:deep(.el-image-viewer__btn:hover) {
  background: rgba(0, 0, 0, 0.7) !important;
}

/* 响应式设计 */
@media (max-width: 1200px) {
  :deep(.workflow-detail-drawer) {
    width: 100% !important;
  }
  
  .ep-title {
    font-size: 24px;
  }
  
  .cover-container {
    height: 200px;
  }
}

@media (max-width: 768px) {
  .ep-detail-body {
    padding: 16px;
  }
  
  .drawer-footer {
    padding: 12px 16px;
    flex-direction: column;
    gap: 12px;
  }
  
  .ep-title {
    font-size: 20px;
    margin-bottom: 12px;
  }
  
  .cover-container {
    height: 180px;
  }
  
  .workflow-info {
    gap: 12px;
  }
  
  .card-header {
    flex-direction: column;
    gap: 12px;
    align-items: flex-start;
  }
  
  .header-title {
    font-size: 14px;
  }
  
  .prism-player {
    height: 200px;
  }
  
  .player-header {
    padding: 12px 16px;
    flex-direction: column;
    gap: 8px;
    align-items: flex-start;
  }
  
  .player-body {
    padding: 12px;
  }
  
  .resource-item {
    flex-direction: column;
    gap: 16px;
    align-items: center;
    text-align: center;
  }
  
  .resource-info {
    flex-direction: column;
    gap: 12px;
    text-align: center;
  }
  
  .gallery-display-grid {
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 12px;
  }
  
  .workflow-data-edit-section,
  .video-edit-section {
    padding: 16px;
    margin: 16px 0;
  }
  
  .data-file-upload,
  .video-file-upload {
    min-height: 120px;
  }
  
  .upload-icon {
    font-size: 24px;
    margin-bottom: 8px;
  }
}

@media (max-width: 480px) {
  .ep-detail-body {
    padding: 12px;
  }
  
  .ep-title {
    font-size: 18px;
  }
  
  .cover-container {
    height: 160px;
  }
  
  .prism-player {
    height: 180px;
  }
  
  .gallery-display-grid {
    grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
    gap: 8px;
  }
  
  .resource-icon-wrapper {
    width: 40px;
    height: 40px;
  }
  
  .resource-icon {
    font-size: 20px;
  }
  
  .resource-text {
    font-size: 14px;
  }
  
  .resource-desc {
    font-size: 12px;
  }
}
</style>