feat: AI分析单页展示 + 主题切换 + 移动端适配
- AI分析页改为直接展示最新报告,历史存数据库 - 新增浅色/深色/系统自动主题切换 - 市场看板、AI分析页适配主题变量 - 移动端表格可滑动、按钮自动换行 - Mermaid图表支持 - Markdown表格渲染支持(remark-gfm)
This commit is contained in:
@@ -17,6 +17,13 @@ export interface AiReport {
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export async function fetchAiLatestReport(): Promise<AiReport> {
|
||||
const resp = await fetch(`${API_BASE}/api/ai-analysis/latest`);
|
||||
if (!resp.ok) throw new Error(`请求失败 (${resp.status})`);
|
||||
const result = await resp.json();
|
||||
return result.data;
|
||||
}
|
||||
|
||||
export async function fetchAiReports(): Promise<AiReport[]> {
|
||||
const resp = await fetch(`${API_BASE}/api/ai-analysis`);
|
||||
if (!resp.ok) throw new Error(`请求失败 (${resp.status})`);
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
|
||||
type Theme = "light" | "dark" | "system";
|
||||
|
||||
function getSystemTheme(): "light" | "dark" {
|
||||
if (typeof window === "undefined") return "light";
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
||||
}
|
||||
|
||||
function getResolvedTheme(theme: Theme): "light" | "dark" {
|
||||
return theme === "system" ? getSystemTheme() : theme;
|
||||
}
|
||||
|
||||
function applyTheme(resolved: "light" | "dark") {
|
||||
const root = document.documentElement;
|
||||
root.classList.remove("light", "dark");
|
||||
root.classList.add(resolved);
|
||||
root.setAttribute("data-theme", resolved);
|
||||
}
|
||||
|
||||
export function useTheme() {
|
||||
const [theme, setThemeState] = useState<Theme>(() => {
|
||||
if (typeof window === "undefined") return "system";
|
||||
return (localStorage.getItem("theme") as Theme) || "system";
|
||||
});
|
||||
|
||||
const [resolved, setResolved] = useState<"light" | "dark">(() => getResolvedTheme(theme));
|
||||
|
||||
const setTheme = useCallback((newTheme: Theme) => {
|
||||
setThemeState(newTheme);
|
||||
localStorage.setItem("theme", newTheme);
|
||||
const r = getResolvedTheme(newTheme);
|
||||
setResolved(r);
|
||||
applyTheme(r);
|
||||
}, []);
|
||||
|
||||
// 初始应用
|
||||
useEffect(() => {
|
||||
applyTheme(resolved);
|
||||
}, []);
|
||||
|
||||
// 监听系统主题变化
|
||||
useEffect(() => {
|
||||
if (theme !== "system") return;
|
||||
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
const handler = () => {
|
||||
const r = getSystemTheme();
|
||||
setResolved(r);
|
||||
applyTheme(r);
|
||||
};
|
||||
mq.addEventListener("change", handler);
|
||||
return () => mq.removeEventListener("change", handler);
|
||||
}, [theme]);
|
||||
|
||||
return { theme, resolved, setTheme };
|
||||
}
|
||||
Reference in New Issue
Block a user