修正首页的内容

This commit is contained in:
xucheng 2026-01-13 15:15:03 +08:00
parent a6f2895dad
commit 4ea47541e9
5 changed files with 59 additions and 49 deletions

View File

@ -309,10 +309,13 @@ async def get_available_sources(market: str):
@router.get("/recent", response_model=List[dict])
async def get_recent_companies(
data_source: str = "Bloomberg",
data_source: str = None,
db: AsyncSession = Depends(get_db)
):
"""获取最近更新的公司列表"""
"""获取最近更新的公司列表
如果不指定 data_source将返回所有数据源的最近更新
"""
return await data_fetcher_service.get_recent_companies(
data_source=data_source,
db=db,

View File

@ -492,24 +492,28 @@ def get_available_data_sources(market: str) -> List[Dict]:
return sources
async def get_recent_companies(
data_source: str,
data_source: Optional[str],
db: AsyncSession,
limit: int = 20
) -> List[Dict]:
"""获取指定数据源下最近更新的公司"""
"""获取最近更新的公司列表
Args:
data_source: 可选的数据源过滤如果为None则返回所有数据源的最近更新
db: 数据库会话
limit: 返回数量限制
"""
query = (
select(Company, DataUpdate.completed_at)
select(Company, DataUpdate.completed_at, DataUpdate.data_source)
.join(DataUpdate, Company.id == DataUpdate.company_id)
.where(
and_(
DataUpdate.data_source == data_source,
DataUpdate.status == 'completed'
)
)
.where(DataUpdate.status == 'completed')
.order_by(DataUpdate.completed_at.desc())
.limit(limit * 3) # Fetch more to handle duplicates
.limit(limit * 5) # Fetch more to handle duplicates
)
if data_source:
query = query.where(DataUpdate.data_source == data_source)
result = await db.execute(query)
rows = result.all()
@ -517,13 +521,14 @@ async def get_recent_companies(
companies = []
for row in rows:
company, completed_at = row
company, completed_at, source = row
if company.id not in seen_ids:
seen_ids.add(company.id)
companies.append({
"market": company.market,
"symbol": company.symbol,
"company_name": company.company_name,
"data_source": source,
"last_update": completed_at.strftime('%Y-%m-%d %H:%M') if completed_at else ""
})
if len(companies) >= limit:

View File

@ -116,7 +116,7 @@ export default function Home() {
</div>
{/* 历史记录 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="w-full">
<HistoryList onSelect={handleCompanySelect} />
</div>
</div>

View File

@ -1,10 +1,8 @@
"use client"
import { useEffect, useState } from "react"
import { getReports } from "@/lib/api"
import { getRecentCompanies } from "@/lib/api"
import { Badge } from "@/components/ui/badge"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Loader2 } from "lucide-react"
import { Loader2, Database } from "lucide-react"
import type { SearchResult } from "@/lib/types"
interface HistoryListProps {
@ -12,59 +10,50 @@ interface HistoryListProps {
}
export function HistoryList({ onSelect }: HistoryListProps) {
const [reports, setReports] = useState<any[]>([])
const [companies, setCompanies] = useState<any[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
getReports().then(setReports).catch(console.error).finally(() => setLoading(false))
getRecentCompanies().then(setCompanies).catch(console.error).finally(() => setLoading(false))
}, [])
if (loading) return <Loader2 className="animate-spin text-muted-foreground" />
if (reports.length === 0) return <div className="text-muted-foreground"></div>
if (companies.length === 0) return <div className="text-muted-foreground"></div>
return (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{reports.map((report: any) => (
<div className="grid gap-4 grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
{companies.map((company: any, index: number) => (
<Card
key={report.id}
key={`${company.symbol}-${index}`}
className="hover:shadow-lg transition-shadow cursor-pointer"
onClick={() => {
if (onSelect) {
onSelect({
symbol: report.symbol,
market: report.market,
company_name: report.company_name
}, report.data_source)
symbol: company.symbol,
market: company.market,
company_name: company.company_name
}, company.data_source)
}
}}
>
<CardHeader>
<CardTitle className="text-lg">{report.company_name}</CardTitle>
<CardHeader className="pb-2">
<div className="flex justify-between items-start">
<CardTitle className="text-lg">{company.company_name}</CardTitle>
<Badge variant="outline">{company.market}</Badge>
</div>
<CardDescription>
{report.market} {report.symbol}
{company.symbol}
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex items-center justify-between">
<span className="text-sm text-muted-foreground">
{new Date(report.created_at).toLocaleString('zh-CN')}
</span>
<Badge variant={
report.status === "completed" ? "default" :
report.status === "in_progress" ? "secondary" :
report.status === "failed" ? "destructive" : "outline"
}>
{report.status === "completed" ? "已完成" :
report.status === "in_progress" ? "进行中" :
report.status === "failed" ? "失败" : "待处理"}
</Badge>
</div>
{report.ai_model && (
<div className="mt-2 text-xs text-muted-foreground">
: {report.ai_model}
<div className="flex items-center justify-between text-sm text-muted-foreground">
<span>{company.last_update}</span>
<div className="flex items-center gap-1">
<Database className="w-3 h-3" />
<span>{company.data_source}</span>
</div>
)}
</div>
</CardContent>
</Card>
))}

View File

@ -163,6 +163,19 @@ export async function getAnalysisHistory(
return res.json()
}
/**
*
*/
export async function getRecentCompanies(dataSource?: string): Promise<any[]> {
let url = `${API_BASE}/data/recent`
if (dataSource) {
url += `?data_source=${dataSource}`
}
const res = await fetch(url)
if (!res.ok) throw new Error("Failed to fetch recent companies")
return res.json()
}
// ========== 兼容性函数 ==========
/**
* API