ResearchTaskPanels.vue 3.1 KB
<script setup lang="ts">
import type { ResearchTask } from '@/types'
import { formatTimeLabel, statusTone } from '@/utils/format'

interface SummaryItem {
  label: string
  value: string
}

defineProps<{
  activeTask: ResearchTask | null
  tasks: ResearchTask[]
  summaryItems: SummaryItem[]
}>()

defineEmits<{
  activate: [taskId: string]
}>()
</script>

<template>
  <div class="research-meta">
    <article class="meta-card">
      <div class="meta-card__head">
        <div>
          <p class="archive-kicker">Current Task</p>
          <h4>{{ activeTask?.venue_name || '尚未创建研究任务' }}</h4>
        </div>
        <span class="archive-chip" :data-tone="statusTone(activeTask?.status || 'draft')">
          <span class="archive-chip__dot" />
          {{ activeTask?.status_label || '草稿' }}
        </span>
      </div>

      <div class="summary-list">
        <div v-for="item in summaryItems" :key="item.label" class="summary-item">
          <span class="archive-kicker">{{ item.label }}</span>
          <strong>{{ item.value }}</strong>
        </div>
      </div>
    </article>

    <article class="meta-card">
      <div class="meta-card__head">
        <div>
          <p class="archive-kicker">History Navigator</p>
          <h4>最近任务切换</h4>
        </div>
      </div>

      <div v-if="tasks.length" class="history-list">
        <button
          v-for="item in tasks.slice(0, 6)"
          :key="item.task_id"
          class="history-item"
          :class="{ 'history-item--active': item.task_id === activeTask?.task_id }"
          type="button"
          @click="$emit('activate', item.task_id)"
        >
          <strong>{{ item.summary_text || item.venue_name }}</strong>
          <span>{{ formatTimeLabel(item.updated_at) }}</span>
        </button>
      </div>

      <div v-else class="archive-empty">
        <p>暂无历史任务。</p>
      </div>
    </article>
  </div>
</template>

<style scoped>
.research-meta,
.summary-list,
.history-list {
  display: grid;
  gap: 16px;
}

.meta-card {
  display: grid;
  gap: 16px;
  padding: 18px;
  border: 1px solid rgba(24, 35, 31, 0.08);
  border-radius: 22px;
  background: rgba(255, 255, 255, 0.66);
}

.meta-card__head {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: flex-start;
}

.meta-card__head h4 {
  margin: 6px 0 0;
  font-size: 18px;
  color: var(--primary);
}

.summary-item {
  display: grid;
  gap: 8px;
}

.summary-item strong {
  color: var(--text);
  line-height: 1.8;
  font-size: 14px;
}

.history-item {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  padding: 14px 16px;
  border: 1px solid rgba(24, 35, 31, 0.08);
  border-radius: 18px;
  background: rgba(251, 247, 240, 0.84);
  color: var(--text);
  text-align: left;
  cursor: pointer;
}

.history-item--active {
  border-color: rgba(141, 103, 56, 0.24);
  background: rgba(141, 103, 56, 0.08);
}

.history-item strong {
  color: var(--primary);
}

.history-item span {
  color: var(--text-soft);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
</style>