feat(frontend): 重构视频分析页面,支持多种搜索方式

主要更新:
- 前端改用 Ant Design 组件(Table、Modal、Select 等)
- 支持三种搜索方式:星图ID、达人unique_id、达人昵称模糊匹配
- 列表页实时调用云图 API 获取 A3 数据和成本指标
- 详情弹窗显示完整 6 大类指标,支持文字复制
- 品牌 API URL 格式修复为查询参数形式
- 优化云图 API 参数格式和会话池管理

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
zfc
2026-01-28 22:01:55 +08:00
co-authored by Claude Opus 4.5
parent f123f68be3
commit 7cd29c5980
25 changed files with 2482 additions and 1324 deletions
+124 -4
View File
@@ -1,26 +1,55 @@
"""
视频分析API路由 (T-024)
GET /api/v1/videos/{item_id}/analysis
GET /api/v1/videos/{item_id}/analysis - 单个视频分析
POST /api/v1/videos/search - 搜索视频列表(支持 star_id / nickname
"""
from fastapi import APIRouter, Depends, HTTPException
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.services.video_analysis import get_video_analysis_data
from app.services.video_analysis import (
get_video_analysis_data,
get_video_base_info,
search_videos_by_star_id,
search_videos_by_unique_id,
search_videos_by_nickname,
get_video_list_with_a3,
)
from app.services.yuntu_api import YuntuAPIError
router = APIRouter(prefix="/videos", tags=["视频分析"])
class SearchRequest(BaseModel):
"""搜索请求"""
type: str # "star_id" | "unique_id" | "nickname"
value: str
class VideoListItem(BaseModel):
"""视频列表项"""
item_id: str
title: str
star_nickname: str
star_unique_id: str
create_date: Optional[str]
hot_type: str
total_play_cnt: int
total_new_a3_cnt: int
total_cost: float
@router.get("/{item_id}/analysis")
async def get_video_analysis(
item_id: str,
db: AsyncSession = Depends(get_db),
):
"""
获取视频分析数据。
获取单个视频分析数据。
返回6大类指标:
- 基础信息 (8字段)
@@ -53,3 +82,94 @@ async def get_video_analysis(
raise HTTPException(status_code=500, detail=f"API Error: {e.message}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}")
@router.post("/search")
async def search_videos(
request: SearchRequest,
db: AsyncSession = Depends(get_db),
):
"""
搜索视频列表。
支持三种搜索方式(均返回列表,点击详情查看完整数据):
- star_id: 星图ID精准匹配
- unique_id: 达人unique_id精准匹配
- nickname: 达人昵称模糊匹配
Args:
request: 搜索请求,包含 type 和 value
Returns:
视频列表(含A3数据和成本指标)
"""
try:
if request.type == "star_id":
# 星图ID查询,返回视频列表
videos = await search_videos_by_star_id(db, request.value)
if not videos:
return {
"success": True,
"type": "list",
"data": [],
"total": 0,
}
# 获取 A3 数据
result = await get_video_list_with_a3(db, videos)
return {
"success": True,
"type": "list",
"data": result,
"total": len(result),
}
elif request.type == "unique_id":
# 达人unique_id查询,返回视频列表
videos = await search_videos_by_unique_id(db, request.value)
if not videos:
return {
"success": True,
"type": "list",
"data": [],
"total": 0,
}
# 获取 A3 数据
result = await get_video_list_with_a3(db, videos)
return {
"success": True,
"type": "list",
"data": result,
"total": len(result),
}
elif request.type == "nickname":
# 昵称模糊查询,返回视频列表
videos = await search_videos_by_nickname(db, request.value)
if not videos:
return {
"success": True,
"type": "list",
"data": [],
"total": 0,
}
# 获取 A3 数据
result = await get_video_list_with_a3(db, videos)
return {
"success": True,
"type": "list",
"data": result,
"total": len(result),
}
else:
raise HTTPException(status_code=400, detail=f"Invalid search type: {request.type}")
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except YuntuAPIError as e:
raise HTTPException(status_code=500, detail=f"API Error: {e.message}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}")