6.0 KiB
Raw Blame History

phase, plan, wave, title, depends_on, files_modified, autonomous, requirements
phase plan wave title depends_on files_modified autonomous requirements
6 2 2 爬虫入库统计 API + 前端监控区域QUAL-06/07
06-01-PLAN.md
app/api/v1/job/job.py
web/src/views/cleaning/monitor.vue
web/src/api/index.js
true
QUAL-06
QUAL-07

Phase 6 Plan 02: 爬虫入库统计 API + 前端监控QUAL-06/07

Objective

QUAL-07 状态确认(已完成)

cleaning/monitor.vue 已包含:

  • 待清洗公司列表(队列表格)
  • 触发清洗
  • 查看结果

QUAL-07 无需额外改动。

QUAL-06 缺口

现有监控页面仅展示公司清洗队列状态,缺少爬虫职位入库的实时统计

  • 各平台最近抓取时间ClickHouse created_at 最大值)
  • 数量趋势(近 7 天每日入库量)
  • 错误状态(失败/去重统计暂不通过 ClickHouse后续可扩展

Must Haves

  • 后端新增 GET /api/v1/job/data/stats 端点,接受 platform(可选)和 days(默认 7参数
    • 返回:各平台 totaltodaylast_ingest_atdaily_counts(列表)
  • 前端 monitor.vue 在现有 4 个 metric-card 上方新增一个"爬虫入库"统计区域:
    • 3 个平台卡片,各显示:总量、今日、最近抓取时间
    • 一个数量趋势表格(近 7 天,按日显示 boss/qcwy/zhilian
  • web/src/api/index.js 新增 getIngestStats 函数
  • 前端 pnpm dev(或工具链验证)可正常加载
  • 全量 pytest 回归 pipenv run python -m pytest tests/ 无失败

Wave 2依赖 Plan 01

Task 2.1: 后端新增 GET /job/data/stats 端点

<read_first>

  • app/api/v1/job/job.py(当前 123 行)
  • app/core/clickhouse.py(获取 client 方式) </read_first>
在 `job.py` 中追加端点:
@router.get("/data/stats", summary="各平台入库统计")
async def get_ingest_stats(
    platform: Optional[PlatformType] = None,
    days: int = 7,
    service: IngestService = Depends(get_ingest_service),
) -> Dict[str, Any]:
    """
    查询各平台 ClickHouse 入库统计:总量、今日、最近入库时间、近 N 天每日趋势
    """
    from app.core.clickhouse import clickhouse_manager
    client = await clickhouse_manager.get_client()
    
    platforms = [platform.value] if platform else ["boss", "qcwy", "zhilian"]
    table_map = {"boss": "boss_job", "qcwy": "qcwy_job", "zhilian": "zhilian_job"}
    
    result = {}
    for p in platforms:
        table = f"job_data.{table_map[p]}"
        try:
            # 总量
            r_total = await client.query(f"SELECT count() FROM {table}")
            total = r_total.result_rows[0][0] if r_total.result_rows else 0
            
            # 今日
            r_today = await client.query(
                f"SELECT count() FROM {table} WHERE toDate(created_at) = today()"
            )
            today = r_today.result_rows[0][0] if r_today.result_rows else 0
            
            # 最近入库时间
            r_last = await client.query(
                f"SELECT max(created_at) FROM {table}"
            )
            last_at = str(r_last.result_rows[0][0]) if r_last.result_rows and r_last.result_rows[0][0] else None
            
            # 近 N 天每日趋势
            r_daily = await client.query(
                f"SELECT toDate(created_at) AS day, count() AS cnt "
                f"FROM {table} "
                f"WHERE created_at >= today() - {days} "
                f"GROUP BY day ORDER BY day DESC"
            )
            daily_counts = [{"date": str(row[0]), "count": row[1]} for row in r_daily.result_rows]
            
            result[p] = {
                "total": total,
                "today": today,
                "last_ingest_at": last_at,
                "daily_counts": daily_counts,
            }
        except Exception as e:
            result[p] = {"error": str(e), "total": 0, "today": 0, "last_ingest_at": None, "daily_counts": []}
    
    return {"code": 200, "data": result}

Task 2.2: 前端新增 getIngestStats API

在 `web/src/api/index.js` 找到已有 API 函数,追加:
getIngestStats: (params) => request.get('/job/data/stats', { params }),

Task 2.3: 前端 monitor.vue 添加爬虫统计区域

在 `monitor.vue` 的 `
` **之前** 插入一个新 section
<!-- 爬虫入库统计 -->
<section class="ingest-grid">
  <n-card
    v-for="p in ingestStats"
    :key="p.platform"
    :bordered="false"
    class="ingest-card"
  >
    <div class="ingest-platform-label">{{ p.label }}</div>
    <div class="ingest-total">{{ p.total.toLocaleString() }}</div>
    <div class="ingest-meta">
      今日 +{{ p.today }} · 最近 {{ p.last_ingest_at || '--' }}
    </div>
  </n-card>
  <n-card :bordered="false" class="ingest-trend-card">
    <div class="ingest-trend-title">近 7 天入库趋势</div>
    <n-data-table
      size="small"
      :columns="trendColumns"
      :data="trendRows"
      :pagination="false"
    />
  </n-card>
</section>

对应 <script setup> 中加入:

  • const ingestStatsRaw = ref({})
  • const fetchIngestStats = async () → 调用 api.getIngestStats()
  • const ingestStats = computed(...) → 格式化三平台卡片数据
  • const trendRows = computed(...) → 转置为按日期行boss/qcwy/zhilian 各列
  • const trendColumns → 日期 + 三平台列
  • refreshAll() 中加入 fetchIngestStats()

Verification

# 后端
pipenv run python -m pytest tests/ -v --tb=short

# 前端(确认 pnpm 就绪,验证构建无报错)
cd web && pnpm install 2>&1 | tail -3

手动验证:

  1. pnpm dev 启动前端
  2. 访问「清洗监控」页面,确认顶部出现三个平台入库卡片和近 7 天趋势表格
  3. 数据加载无报错,最近入库时间正确显示格式化后的时间