|
1 | 1 | import type React from 'react'; |
2 | 2 | import { useCallback, useEffect, useMemo, useState } from 'react'; |
3 | 3 | import { useNavigate } from 'react-router-dom'; |
| 4 | +import { systemConfigApi } from '../api/systemConfig'; |
4 | 5 | import { ApiErrorAlert, ConfirmDialog, Button, EmptyState, InlineAlert } from '../components/common'; |
5 | 6 | import { DashboardStateBlock } from '../components/dashboard'; |
6 | 7 | import { StockAutocomplete } from '../components/StockAutocomplete'; |
7 | 8 | import { HistoryList } from '../components/history'; |
8 | 9 | import { ReportMarkdown, ReportSummary } from '../components/report'; |
9 | 10 | import { TaskPanel } from '../components/tasks'; |
10 | 11 | import { useDashboardLifecycle, useHomeDashboardState } from '../hooks'; |
| 12 | +import type { SetupStatusResponse } from '../types/systemConfig'; |
11 | 13 | import { getReportText, normalizeReportLanguage } from '../utils/reportLanguage'; |
12 | 14 |
|
13 | 15 | const HomePage: React.FC = () => { |
14 | 16 | const navigate = useNavigate(); |
15 | 17 | const [sidebarOpen, setSidebarOpen] = useState(false); |
16 | 18 | const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); |
| 19 | + const [setupStatus, setSetupStatus] = useState<SetupStatusResponse | null>(null); |
17 | 20 |
|
18 | 21 | const { |
19 | 22 | query, |
@@ -55,8 +58,38 @@ const HomePage: React.FC = () => { |
55 | 58 | useEffect(() => { |
56 | 59 | document.title = '每日选股分析 - DSA'; |
57 | 60 | }, []); |
| 61 | + |
| 62 | + useEffect(() => { |
| 63 | + let active = true; |
| 64 | + systemConfigApi.getSetupStatus() |
| 65 | + .then((status) => { |
| 66 | + if (active) { |
| 67 | + setSetupStatus(status); |
| 68 | + } |
| 69 | + }) |
| 70 | + .catch(() => { |
| 71 | + if (active) { |
| 72 | + setSetupStatus(null); |
| 73 | + } |
| 74 | + }); |
| 75 | + |
| 76 | + return () => { |
| 77 | + active = false; |
| 78 | + }; |
| 79 | + }, []); |
| 80 | + |
58 | 81 | const reportLanguage = normalizeReportLanguage(selectedReport?.meta.reportLanguage); |
59 | 82 | const reportText = getReportText(reportLanguage); |
| 83 | + const setupNeedsAction = setupStatus ? !setupStatus.isComplete : false; |
| 84 | + const setupMissingLabels = useMemo(() => { |
| 85 | + if (!setupStatus) { |
| 86 | + return ''; |
| 87 | + } |
| 88 | + const requiredNeedsAction = setupStatus.checks |
| 89 | + .filter((check) => check.required && check.status === 'needs_action') |
| 90 | + .map((check) => check.title); |
| 91 | + return requiredNeedsAction.slice(0, 3).join('、'); |
| 92 | + }, [setupStatus]); |
60 | 93 |
|
61 | 94 | useDashboardLifecycle({ |
62 | 95 | loadInitialHistory, |
@@ -235,6 +268,31 @@ const HomePage: React.FC = () => { |
235 | 268 | </div> |
236 | 269 | ) : null} |
237 | 270 |
|
| 271 | + {setupNeedsAction ? ( |
| 272 | + <div className="px-3 pb-2 md:px-4"> |
| 273 | + <InlineAlert |
| 274 | + variant="warning" |
| 275 | + title="基础配置未完成" |
| 276 | + message={ |
| 277 | + setupMissingLabels |
| 278 | + ? `还缺少 ${setupMissingLabels},完成后即可开始最小可用分析。` |
| 279 | + : '还缺少基础配置,完成后即可开始最小可用分析。' |
| 280 | + } |
| 281 | + action={( |
| 282 | + <Button |
| 283 | + type="button" |
| 284 | + variant="secondary" |
| 285 | + size="sm" |
| 286 | + onClick={() => navigate('/settings')} |
| 287 | + > |
| 288 | + 去配置 |
| 289 | + </Button> |
| 290 | + )} |
| 291 | + className="rounded-xl px-3 py-2 text-xs shadow-none" |
| 292 | + /> |
| 293 | + </div> |
| 294 | + ) : null} |
| 295 | + |
238 | 296 | <div className="flex-1 flex min-h-0 overflow-hidden"> |
239 | 297 | <div className="hidden min-h-0 w-64 shrink-0 flex-col overflow-hidden pl-4 pb-4 md:flex lg:w-72"> |
240 | 298 | {sidebarContent} |
|
0 commit comments