CrawlerPanel.vue 4.2 KB
<script setup lang="ts">
import { computed } from 'vue'

import SectionHeading from '@/components/common/SectionHeading.vue'
import CrawlerControlForm from '@/components/crawler/CrawlerControlForm.vue'
import CrawlerPlatformStrip from '@/components/crawler/CrawlerPlatformStrip.vue'
import CrawlerStatusDeck from '@/components/crawler/CrawlerStatusDeck.vue'
import type {
  CrawlerFlowStep,
  CrawlerFormState,
  CrawlerLogEntry,
  CrawlerOptionsResponse,
  CrawlerPlatformState,
  CrawlerPrimaryAction,
  CrawlerStateResponse,
  CrawlerSummaryItem,
} from '@/types'
import { statusTone } from '@/utils/format'

const props = defineProps<{
  options: CrawlerOptionsResponse
  form: CrawlerFormState
  snapshot: CrawlerStateResponse
  selectedPlatformState: CrawlerPlatformState | null
  availableLoginTypes: CrawlerOptionsResponse['login_types']
  availableCrawlerTypes: CrawlerOptionsResponse['crawler_types']
  capabilityHint: string
  validationIssues: string[]
  workflowSteps: CrawlerFlowStep[]
  primaryAction: CrawlerPrimaryAction
  missionSummary: CrawlerSummaryItem[]
  selectedQrCode: string
  lastLoginConfig: Record<string, unknown> | null
  lastCrawlConfig: Record<string, unknown> | null
  canStartLogin: boolean
  canStartCrawler: boolean
  loading: boolean
  acting: boolean
  collapsed: boolean
}>()

const emit = defineEmits<{
  'update:form': [value: CrawlerFormState]
  'update:collapsed': [value: boolean]
  checkLogin: []
  startLogin: []
  cancelLogin: []
  startCrawler: []
  stopCrawler: []
  restoreLastLogin: []
  restoreLastCrawl: []
}>()

const visibleLogs = computed<CrawlerLogEntry[]>(() => {
  if (props.snapshot.crawler.logs.length > 0) {
    return props.snapshot.crawler.logs
  }
  return props.selectedPlatformState?.logs ?? []
})
</script>

<template>
  <section class="panel crawler-shell">
    <SectionHeading
      kicker="Collection Center"
      title="采集中心"
      description="把平台登录、采集参数、执行反馈和最近配置串成一条清晰的操作流,让首次使用和重复执行都更顺手。"
    >
      <template #actions>
        <span class="status-chip" :data-tone="statusTone(snapshot.crawler.status)">
          {{ snapshot.crawler.message || '空闲' }}
        </span>
        <el-button plain @click="$emit('update:collapsed', !collapsed)">
          {{ collapsed ? '展开采集面板' : '收起采集面板' }}
        </el-button>
      </template>
    </SectionHeading>

    <CrawlerPlatformStrip
      :platforms="snapshot.login.platforms"
      :selected-platform="form.platform"
      @select="$emit('update:form', { ...form, platform: $event })"
    />

    <div v-show="!collapsed" class="crawler-body">
      <CrawlerControlForm
        :options="options"
        :form="form"
        :selected-platform-state="selectedPlatformState"
        :available-login-types="availableLoginTypes"
        :available-crawler-types="availableCrawlerTypes"
        :capability-hint="capabilityHint"
        :validation-issues="validationIssues"
        :workflow-steps="workflowSteps"
        :primary-action="primaryAction"
        :last-login-config="lastLoginConfig"
        :last-crawl-config="lastCrawlConfig"
        :can-start-login="canStartLogin"
        :can-start-crawler="canStartCrawler"
        :acting="acting"
        @update:form="$emit('update:form', $event)"
        @check-login="$emit('checkLogin')"
        @start-login="$emit('startLogin')"
        @cancel-login="$emit('cancelLogin')"
        @start-crawler="$emit('startCrawler')"
        @stop-crawler="$emit('stopCrawler')"
        @restore-last-login="$emit('restoreLastLogin')"
        @restore-last-crawl="$emit('restoreLastCrawl')"
      />

      <CrawlerStatusDeck
        :selected-platform-state="selectedPlatformState"
        :capability-hint="capabilityHint"
        :snapshot="snapshot"
        :validation-issues="validationIssues"
        :workflow-steps="workflowSteps"
        :primary-action="primaryAction"
        :mission-summary="missionSummary"
        :selected-qr-code="selectedQrCode"
        :loading="loading"
        :visible-logs="visibleLogs"
      />
    </div>
  </section>
</template>

<style scoped>
.crawler-shell {
  display: grid;
  gap: 22px;
}

.crawler-body {
  display: grid;
  gap: 18px;
}
</style>