<template>
  <PageShell theme="dark">
    <div class="brand-page">
      <header class="top-bar">
        <div class="logo-area">
          <span class="app-name">数富AI-亚马逊</span>
          <router-link to="/home" class="btn-home">返回首页</router-link>
        </div>

        <div class="nav-tabs">
          <div class="nav-tab-group">
            <button type="button" class="nav-tab" :class="{ active: activeTab === 'brand' }"
              @click="activeTab = 'brand'">
              品牌检测
            </button>
            <button type="button" class="nav-tab" :class="{ active: activeTab === 'dedupe' }"
              @click="activeTab = 'dedupe'">
              数据去重
            </button>
            <button type="button" class="nav-tab" :class="{ active: activeTab === 'convert' }"
              @click="activeTab = 'convert'">
              格式转换
            </button>
            <button type="button" class="nav-tab" :class="{ active: activeTab === 'split' }"
              @click="activeTab = 'split'">
              数据拆分
            </button>
          </div>
        </div>
      </header>

      <div v-if="activeTab === 'brand'" class="main-content">
        <aside class="left-panel">
          <div class="section-title">选择文件</div>
          <div class="upload-zone">
            <div class="hint">选择 .xlsx 文件或文件夹（将读取该文件夹下所有 xlsx）</div>
            <div class="btns">
              <button type="button" class="opt-btn" @click="selectFiles">选择 Excel 文件</button>
              <button type="button" class="opt-btn" @click="selectFolder">选择文件夹</button>
            </div>

            <el-alert v-if="!hasPywebviewSupport" class="desktop-alert" type="warning" :closable="false"
              title="当前环境未检测到 pywebview，文件选择与本地保存能力需要在桌面端使用。" />

            <div class="selected-files">
              <template v-if="selectedPaths.length">
                <span v-for="path in displayPaths" :key="path">{{ path }}</span>
                <span v-if="selectedPaths.length > displayPaths.length" class="more-line">
                  还有 {{ selectedPaths.length - displayPaths.length }} 个文件未展开显示
                </span>
              </template>
              <span v-else>暂未选择文件</span>
            </div>
          </div>

          <div class="section-title">运行方式</div>
          <div class="option-group">
            <label class="radio-item" :class="{ active: runMode === 'immediate' }">
              <input v-model="runMode" type="radio" value="immediate" />
              <div>
                <span class="label">立即运行</span>
                <div class="desc">立即执行，执行完成后可下载结果</div>
              </div>
            </label>

            <label class="radio-item" :class="{ active: runMode === 'task' }">
              <input v-model="runMode" type="radio" value="task" />
              <div>
                <span class="label">添加任务</span>
                <div class="desc">数量较多时建议添加任务，后台执行，可在右侧任务队列查看状态与下载结果</div>
              </div>
            </label>
          </div>

          <div class="section-title">匹配方式</div>
          <div class="option-group">
            <label class="radio-item" :class="{ active: matchStrategy === 'Terms' }">
              <input v-model="matchStrategy" type="radio" value="Terms" />
              <div>
                <span class="label">精确匹配表达式</span>
                <div class="desc">使用精确匹配，适合严格匹配品牌名称</div>
              </div>
            </label>

            <label class="radio-item" :class="{ active: matchStrategy === 'Simple' }">
              <input v-model="matchStrategy" type="radio" value="Simple" />
              <div>
                <span class="label">嵌入（结果包含输入的词语）</span>
                <div class="desc">使用嵌入策略，结果中包含输入的品牌词语</div>
              </div>
            </label>
          </div>

          <div class="run-row">
            <button type="button" class="btn-run" :disabled="running" @click="submitRun">
              {{ runMode === 'immediate' ? '立即运行' : '添加任务' }}
            </button>
            <span v-if="running" class="loading-msg">生成中，请稍候…</span>
            <button v-if="activeTaskId" type="button" class="btn-cancel-run" @click="cancelActiveTask">
              取消生成
            </button>
          </div>

          <div v-if="activeTaskId" class="progress-wrap">
            <div class="progress-bar-bg">
              <div class="progress-bar-fill" :style="{ width: `${progressPercent}%` }"></div>
            </div>
            <span class="progress-text">{{ progressText }}</span>
          </div>

          <button type="button" class="template-download-row" @click="downloadTemplateXlsx">
            <span class="template-download-icon" aria-hidden="true">
              <svg viewBox="0 0 24 24" fill="none">
                <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"
                  stroke="rgba(255,255,255,0.92)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
                <path d="M14 2v6h6" stroke="rgba(255,255,255,0.92)" stroke-width="1.8" stroke-linecap="round"
                  stroke-linejoin="round" />
                <path d="M8 13h8M8 17h5" stroke="rgba(255,255,255,0.86)" stroke-width="1.5" stroke-linecap="round" />
              </svg>
            </span>
            <span class="template-download-text">
              <span class="title">模板下载</span>
              <span class="hint">品牌文档格式_模板.xlsx · 点击选择保存位置</span>
            </span>
          </button>

          <button type="button" class="template-download-row" @click="downloadTemplateZip">
            <span class="template-download-icon" aria-hidden="true">
              <svg viewBox="0 0 24 24" fill="none">
                <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"
                  stroke="rgba(255,255,255,0.92)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
                <path d="M14 2v6h6" stroke="rgba(255,255,255,0.92)" stroke-width="1.8" stroke-linecap="round"
                  stroke-linejoin="round" />
                <path d="M4 8h16M7 12h10M7 16h7" stroke="rgba(255,255,255,0.86)" stroke-width="1.5"
                  stroke-linecap="round" />
              </svg>
            </span>
            <span class="template-download-text">
              <span class="title">模板2下载</span>
              <span class="hint">以文件夹方式上传.zip · 点击下载</span>
            </span>
          </button>
        </aside>

        <section class="right-panel">
          <div class="panel-header">任务队列</div>

          <div class="task-list-wrap">
            <div v-if="tasks.length === 0" class="empty-tasks">暂无任务</div>

            <ul v-else class="task-list">
              <li v-for="task in tasks" :key="task.id" class="task-item">
                <div class="left">
                  <span class="id" :title="getTaskTitle(task)">
                    {{ shorten(getTaskTitle(task), 20) }}
                  </span>
                  <div class="files">{{ (task.file_paths?.length || 0) }} 个文件</div>
                  <div class="time">{{ task.created_at || '-' }}</div>
                </div>

                <div class="task-right">
                  <div v-if="task.status === 'running' && (task.progress_total || 0) > 0" class="inline-progress">
                    <div class="progress-bar-bg small">
                      <div class="progress-bar-fill" :style="{ width: `${getTaskProgressPercent(task)}%` }"></div>
                    </div>
                    <span class="inline-progress-text">
                      {{ task.progress_current || 0 }} / {{ task.progress_total || 0 }}
                    </span>
                  </div>

                  <span class="status" :class="task.status || 'pending'">
                    {{ getStatusLabel(task.status) }}
                  </span>

                  <button v-if="task.status === 'running'" type="button" class="btn-cancel"
                    @click="cancelTask(task.id)">
                    取消
                  </button>

                  <button v-if="task.result_paths?.zip_url" type="button" class="download"
                    @click="downloadTaskResult(task)">
                    下载结果
                  </button>

                  <button type="button" class="btn-delete" @click="removeTask(task.id)">删除</button>
                </div>
              </li>
            </ul>
          </div>
        </section>
      </div>

      <BrandDedupeTab v-else-if="activeTab === 'dedupe'" />
      <BrandConvertTab v-else-if="activeTab === 'convert'" />
      <BrandSplitTab v-else-if="activeTab === 'split'" />
    </div>
  </PageShell>
</template>

<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import {
  cancelBrandTask,
  createBrandTask,
  createBrandTaskEvents,
  deleteBrandTask,
  expandBrandFolder,
  getBrandTask,
  getBrandTaskDownloadUrl,
  getBrandTasks,
  getBrandTemplateXlsxUrl,
  getBrandTemplateZipUrl,
  runBrandNow,
  type BrandTaskItem,
} from '@/shared/api/brand'
import { getPywebviewApi, hasPywebview } from '@/shared/bridges/pywebview'
import BrandDedupeTab from '@/pages/brand/components/BrandDedupeTab.vue'
import BrandConvertTab from '@/pages/brand/components/BrandConvertTab.vue'
import BrandSplitTab from '@/pages/brand/components/BrandSplitTab.vue'

const hasPywebviewSupport = hasPywebview()
const activeTab = ref<'brand' | 'dedupe' | 'convert' | 'split'>('brand')
const selectedPaths = ref<string[]>([])
const runMode = ref<'immediate' | 'task'>('immediate')
const matchStrategy = ref<'Terms' | 'Simple'>('Terms')
const tasks = ref<BrandTaskItem[]>([])
const running = ref(false)
const activeTaskId = ref<string | null>(null)
const progressCurrent = ref(0)
const progressTotal = ref(0)
const progressStatus = ref<'running' | 'success' | 'failed' | 'cancelled'>('running')

let taskEvents: EventSource | null = null
let pollTimer: number | null = null
let taskRefreshTimer: number | null = null

const displayPaths = computed(() => selectedPaths.value.slice(0, 8))
const progressPercent = computed(() => {
  if (!progressTotal.value) return progressStatus.value === 'running' ? 12 : 100
  return Math.min(100, Math.round((progressCurrent.value / progressTotal.value) * 100))
})

const progressText = computed(() => {
  if (progressStatus.value === 'success') return '已完成'
  if (progressStatus.value === 'failed') return '失败'
  if (progressStatus.value === 'cancelled') return '已取消'
  if (!progressTotal.value) return '生成中...'
  return `${progressCurrent.value} / ${progressTotal.value}`
})

function getTaskTitle(task: BrandTaskItem) {
  return (task.desc || '').trim() || `任务 #${task.id}`
}

function shorten(value: string, maxLength: number) {
  return value.length > maxLength ? `${value.slice(0, maxLength)}...` : value
}

function getStatusLabel(status?: string) {
  const statusMap: Record<string, string> = {
    pending: '等待中',
    running: '执行中',
    success: '已完成',
    failed: '失败',
    cancelled: '已取消',
  }
  return statusMap[(status || '').toLowerCase()] || (status || '-')
}

function getTaskProgressPercent(task: BrandTaskItem) {
  const current = task.progress_current || 0
  const total = task.progress_total || 0
  return total ? Math.min(100, Math.round((current / total) * 100)) : 0
}

function stopTaskMonitor() {
  activeTaskId.value = null
  running.value = false
  if (taskEvents) {
    taskEvents.close()
    taskEvents = null
  }
  if (pollTimer !== null) {
    window.clearInterval(pollTimer)
    pollTimer = null
  }
}

async function loadTasks() {
  try {
    const result = await getBrandTasks()
    tasks.value = result.success && Array.isArray(result.items) ? result.items : []
  } catch {
    tasks.value = []
  }
}

async function refreshMonitoredTask(taskId: string | number) {
  const result = await getBrandTask(taskId)
  if (!result.success || !result.task) return

  const task = result.task
  progressCurrent.value = task.progress_current || 0
  progressTotal.value = task.progress_total || 0

  const status = (task.status || '').toLowerCase()
  if (status === 'success' || status === 'failed' || status === 'cancelled') {
    progressStatus.value = status as typeof progressStatus.value
    stopTaskMonitor()
    await loadTasks()
    if (status === 'success') ElMessage.success('生成完成，可下载结果')
    if (status === 'failed') ElMessage.error('生成失败')
    if (status === 'cancelled') ElMessage.info('已取消')
  }
}

function monitorTask(taskId: string) {
  stopTaskMonitor()
  activeTaskId.value = taskId
  running.value = true
  progressCurrent.value = 0
  progressTotal.value = 0
  progressStatus.value = 'running'

  taskEvents = createBrandTaskEvents(taskId)
  taskEvents.onmessage = async (event) => {
    try {
      const data = JSON.parse(event.data) as { status?: string }
      const status = (data.status || '').toLowerCase()
      if (status === 'success' || status === 'failed' || status === 'cancelled') {
        progressStatus.value = status as typeof progressStatus.value
        stopTaskMonitor()
        await loadTasks()
      }
    } catch {
      // ignore invalid SSE payload
    }
  }

  taskEvents.onerror = () => {
    if (taskEvents) {
      taskEvents.close()
      taskEvents = null
    }
  }

  refreshMonitoredTask(taskId).catch(() => undefined)
  pollTimer = window.setInterval(() => {
    refreshMonitoredTask(taskId).catch(() => undefined)
  }, 5000)
}

async function selectFiles() {
  const api = getPywebviewApi()
  if (!api?.select_brand_xlsx_files) {
    ElMessage.warning('当前环境不支持文件选择，请在桌面端打开')
    return
  }

  try {
    const paths = await api.select_brand_xlsx_files()
    if (paths?.length) {
      selectedPaths.value = paths
      ElMessage.success(`已选择 ${paths.length} 个文件`)
    }
  } catch (error) {
    ElMessage.error(error instanceof Error ? error.message : '选择失败')
  }
}

async function selectFolder() {
  const api = getPywebviewApi()
  if (!api?.select_brand_folder) {
    ElMessage.warning('当前环境不支持文件夹选择，请在桌面端打开')
    return
  }

  try {
    const folder = await api.select_brand_folder()
    if (!folder) return

    const result = await expandBrandFolder(folder)
    if (result.success && result.paths?.length) {
      selectedPaths.value = result.paths
      ElMessage.success(`已选择文件夹内 ${result.paths.length} 个 xlsx 文件`)
      return
    }

    ElMessage.warning(result.error || '该文件夹下没有 xlsx 文件')
  } catch (error) {
    ElMessage.error(error instanceof Error ? error.message : '选择失败')
  }
}

async function downloadTemplateXlsx() {
  const api = getPywebviewApi()
  if (api?.save_template_xlsx) {
    try {
      const result = await api.save_template_xlsx()
      if (result.success) {
        ElMessage.success(`模板已保存至：${result.path || ''}`)
      } else if (result.error && result.error !== '用户取消') {
        ElMessage.error(result.error || '保存失败')
      }
      return
    } catch (error) {
      ElMessage.error(error instanceof Error ? error.message : '下载失败')
      return
    }
  }

  window.location.href = getBrandTemplateXlsxUrl()
}

async function downloadTemplateZip() {
  const api = getPywebviewApi()
  if (api?.save_template_zip) {
    try {
      const result = await api.save_template_zip()
      if (result.success) {
        ElMessage.success(`模板已保存至：${result.path || ''}`)
      } else if (result.error && result.error !== '用户取消') {
        ElMessage.error(result.error || '保存失败')
      }
      return
    } catch (error) {
      ElMessage.error(error instanceof Error ? error.message : '下载失败')
      return
    }
  }

  window.location.href = getBrandTemplateZipUrl()
}

async function submitRun() {
  if (!selectedPaths.value.length) {
    ElMessage.warning('请先选择 Excel 文件或文件夹')
    return
  }

  try {
    if (runMode.value === 'immediate') {
      running.value = true
      const result = await runBrandNow(selectedPaths.value, matchStrategy.value)
      if (result.success && result.task_id) {
        monitorTask(result.task_id)
        await loadTasks()
        return
      }

      running.value = false
      ElMessage.error(result.error || '运行失败')
      return
    }

    const result = await createBrandTask(selectedPaths.value, matchStrategy.value)
    if (result.success) {
      ElMessage.success('任务已添加，请在任务队列查看')
      await loadTasks()
      return
    }

    ElMessage.error(result.error || '添加失败')
  } catch (error) {
    running.value = false
    ElMessage.error(error instanceof Error ? error.message : '请求失败')
  }
}

async function cancelTask(taskId: string | number) {
  const result = await cancelBrandTask(taskId)
  if (result.success) {
    ElMessage.success('已取消')
    if (String(activeTaskId.value) === String(taskId)) {
      progressStatus.value = 'cancelled'
      stopTaskMonitor()
    }
    await loadTasks()
    return
  }

  ElMessage.error(result.error || '取消失败')
}

async function cancelActiveTask() {
  if (!activeTaskId.value) return
  await cancelTask(activeTaskId.value)
}

async function removeTask(taskId: string | number) {
  const result = await deleteBrandTask(taskId)
  if (result.success) {
    ElMessage.success('已删除')
    await loadTasks()
    return
  }

  ElMessage.error(result.error || '删除失败')
}

async function downloadTaskResult(task: BrandTaskItem) {
  const zipUrl = task.result_paths?.zip_url
  if (!zipUrl) {
    ElMessage.error('无法获取下载地址')
    return
  }

  const api = getPywebviewApi()
  const filename = `brand_task_${task.id}.zip`

  if (api?.save_file_from_url) {
    try {
      const result = await api.save_file_from_url(zipUrl, filename)
      if (result.success) {
        ElMessage.success(`已保存：${result.path || filename}`)
      } else if (result.error && result.error !== '用户取消') {
        ElMessage.error(result.error)
      }
      return
    } catch (error) {
      ElMessage.error(error instanceof Error ? error.message : '保存失败')
      return
    }
  }

  window.open(getBrandTaskDownloadUrl(task.id), '_blank')
}

onMounted(() => {
  document.title = '亚马逊 - 数富AI'
  loadTasks().catch(() => undefined)
  taskRefreshTimer = window.setInterval(() => {
    loadTasks().catch(() => undefined)
  }, 10000)
})

onBeforeUnmount(() => {
  stopTaskMonitor()
  if (taskRefreshTimer !== null) {
    window.clearInterval(taskRefreshTimer)
    taskRefreshTimer = null
  }
})
</script>

<style scoped>
.brand-page {
  min-height: 100vh;
  background: #0d0d0d;
  color: #e0e0e0;
  font-family: "Microsoft YaHei", "Noto Serif SC", "SimSun", "Songti SC", serif;
  font-weight: 700;
}

.top-bar {
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  border-bottom: 1px solid #2a2a2a;
}

.logo-area {
  display: flex;
  align-items: center;
  gap: 10px;
}

.app-name {
  font-size: 18px;
  font-weight: 600;
  color: #fff;
}

.btn-home {
  font-size: 13px;
  color: #999;
  text-decoration: none;
  padding: 8px 12px;
  border-radius: 6px;
  transition: all 0.2s ease;
}

.btn-home:hover {
  color: #fff;
  background: #2a2a2a;
}

.nav-tabs {
  display: flex;
  align-items: center;
}

.nav-tab-group {
  display: flex;
  align-items: center;
  background: rgba(77, 72, 72, 0.99);
  border-radius: 10px;
}

.nav-tab {
  padding: 8px 14px;
  font-size: 13px;
  color: #9fb9d3;
  background: transparent;
  border: none;
  border-radius: 6px;
}

.nav-tab:hover {
  color: #d8ecff;
  background: rgba(52, 152, 219, 0.12);
}

.nav-tab.active {
  color: #3498db;
  background: rgba(52, 152, 219, 0.2);
}

.main-content {
  display: flex;
  height: calc(100vh - 56px);
}

.left-panel {
  width: 380px;
  background: #1e1e1e;
  padding: 20px;
  overflow-y: auto;
  border-right: 1px solid #2a2a2a;
}

.right-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: #1a1a1a;
}

.section-title {
  font-size: 13px;
  color: #bbb;
  margin-bottom: 10px;
}

.upload-zone {
  border: 1px dashed #3a3a3a;
  border-radius: 10px;
  padding: 24px;
  text-align: center;
  background: #252525;
  margin-bottom: 20px;
  transition: all 0.2s ease;
}

.upload-zone:hover {
  border-color: #3498db;
  background: #2a2a2a;
}

.hint {
  color: #888;
  font-size: 13px;
  margin-bottom: 12px;
  line-height: 1.5;
}

.btns {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}

.opt-btn,
.btn-run,
.btn-cancel-run,
.btn-cancel,
.btn-delete,
.download {
  border: none;
  cursor: pointer;
  transition: all 0.2s ease;
}

.opt-btn {
  padding: 8px 16px;
  font-size: 13px;
  color: #ccc;
  background: #2a2a2a;
  border: 1px solid #3a3a3a;
  border-radius: 6px;
}

.opt-btn:hover {
  color: #3498db;
  background: #333;
  border-color: #3498db;
}

.desktop-alert {
  margin-top: 14px;
  text-align: left;
}

.selected-files {
  margin-top: 14px;
  font-size: 12px;
  color: #888;
  max-height: 112px;
  overflow-y: auto;
  text-align: left;
}

.selected-files span {
  display: block;
  margin: 4px 0;
  word-break: break-all;
}

.more-line {
  color: #b8c1cc;
}

.option-group {
  margin-bottom: 20px;
}

.radio-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  padding: 10px 12px;
  border-radius: 8px;
  background: #252525;
  border: 1px solid #2a2a2a;
  margin-bottom: 8px;
  transition: all 0.2s ease;
}

.radio-item:hover,
.radio-item.active {
  background: #2a2a2a;
  border-color: #3a3a3a;
}

.radio-item input {
  margin-top: 3px;
}

.label {
  font-weight: 500;
  color: #e0e0e0;
  font-size: 13px;
}

.desc {
  font-size: 12px;
  color: #888;
  margin-top: 2px;
  line-height: 1.5;
  font-weight: 400;
}

.run-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 12px;
  margin-top: 16px;
}

.btn-run {
  padding: 10px 22px;
  background: #3498db;
  color: #fff;
  border-radius: 8px;
  font-size: 14px;
}

.btn-run:hover {
  background: #2980b9;
}

.btn-run:disabled {
  background: #555;
  color: #999;
  cursor: not-allowed;
}

.loading-msg {
  color: #3498db;
  font-size: 13px;
}

.btn-cancel-run {
  padding: 9px 18px;
  border-radius: 8px;
  background: rgba(231, 126, 35, 0.18);
  color: #f0ad4e;
}

.btn-cancel-run:hover,
.btn-cancel:hover {
  background: rgba(231, 126, 35, 0.28);
}

.progress-wrap {
  margin-top: 14px;
}

.progress-bar-bg {
  height: 8px;
  border-radius: 999px;
  background: #2d2d2d;
  overflow: hidden;
}

.progress-bar-bg.small {
  width: 180px;
  height: 6px;
}

.progress-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, #3498db 0%, #5dade2 100%);
  border-radius: inherit;
  transition: width 0.2s ease;
}

.progress-text,
.inline-progress-text {
  display: inline-block;
  margin-top: 8px;
  font-size: 12px;
  color: #888;
}

.template-download-row {
  width: 100%;
  margin-top: 16px;
  padding: 14px 16px;
  background: linear-gradient(135deg, #252525 0%, #1e2a1e 100%);
  border: 1px solid #2a3a2a;
  border-radius: 10px;
  display: flex;
  align-items: center;
  gap: 14px;
  transition: all 0.25s ease;
  color: inherit;
}

.template-download-row:hover {
  border-color: #2e7d32;
  background: linear-gradient(135deg, #2a2a2a 0%, #243324 100%);
  box-shadow: 0 4px 12px rgba(46, 125, 50, 0.15);
}

.template-download-row:hover .title {
  color: #2ecc71;
}

.template-download-row:hover .template-download-icon {
  transform: scale(1.05);
  box-shadow: 0 6px 16px rgba(46, 125, 50, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

.template-download-icon {
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  border-radius: 10px;
  background: linear-gradient(145deg, #1b5e20 0%, #2e7d32 50%, #388e3c 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px rgba(46, 125, 50, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.1);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.template-download-icon svg {
  width: 28px;
  height: 28px;
}

.template-download-text .title {
  font-size: 14px;
  color: #e0e0e0;
  font-weight: 600;
  display: block;
}

.template-download-text .hint {
  font-size: 12px;
  color: #888;
  margin-top: 2px;
  font-weight: 400;
  margin-bottom: 0;
}

.panel-header {
  padding: 16px 20px;
  border-bottom: 1px solid #2a2a2a;
  font-size: 15px;
  font-weight: 600;
  color: #ddd;
}

.task-list-wrap {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
}

.task-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.task-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 16px;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  margin-bottom: 10px;
  background: #1e1e1e;
}

.left {
  flex: 1;
  min-width: 0;
}

.id {
  display: inline-block;
  font-weight: 600;
  color: #e0e0e0;
  font-size: 13px;
}

.files {
  font-size: 12px;
  color: #888;
  margin-top: 4px;
}

.time {
  font-size: 12px;
  color: #666;
  margin-top: 2px;
}

.task-right {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.status {
  padding: 4px 10px;
  border-radius: 6px;
  font-size: 12px;
  white-space: nowrap;
}

.status.pending {
  background: rgba(255, 193, 7, 0.2);
  color: #d4a500;
}

.status.running {
  background: rgba(52, 152, 219, 0.2);
  color: #3498db;
}

.status.success {
  background: rgba(46, 204, 113, 0.18);
  color: #2ecc71;
}

.status.failed {
  background: rgba(231, 76, 60, 0.18);
  color: #ff6b6b;
}

.status.cancelled {
  background: rgba(149, 165, 166, 0.18);
  color: #b2bec3;
}

.btn-cancel,
.btn-delete,
.download {
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 12px;
}

.btn-cancel {
  background: rgba(231, 126, 35, 0.18);
  color: #f0ad4e;
}

.btn-delete {
  background: #2a2a2a;
  color: #b8b8b8;
}

.btn-delete:hover {
  background: #343434;
  color: #fff;
}

.download {
  background: rgba(52, 152, 219, 0.18);
  color: #69b6ff;
}

.download:hover {
  background: rgba(52, 152, 219, 0.28);
}

.empty-tasks {
  color: #666;
  font-size: 13px;
  padding: 24px 8px;
}

@media (max-width: 1100px) {
  .main-content {
    flex-direction: column;
    height: auto;
  }

  .left-panel {
    width: 100%;
    border-right: none;
    border-bottom: 1px solid #2a2a2a;
  }

  .right-panel {
    min-height: 420px;
  }

  .task-item {
    flex-direction: column;
    align-items: flex-start;
  }

  .task-right {
    width: 100%;
    justify-content: flex-start;
  }

  .progress-bar-bg.small {
    width: 100%;
  }
}
</style>