diff --git a/server/main.go b/server/main.go
index e41b3e9..aaa6bc0 100644
--- a/server/main.go
+++ b/server/main.go
@@ -28,18 +28,24 @@ func main() {
}
fmt.Println("Database connected successfully")
- // 异步创建常用索引,避免首次查询慢
+ // 异步创建常用索引,已存在则跳过
go func() {
time.Sleep(3 * time.Second)
- indexes := []string{
- "ALTER TABLE stock_daily ADD INDEX idx_sd_date (date)",
- "ALTER TABLE stock_daily ADD INDEX idx_sd_code_date (code, date)",
- "ALTER TABLE stock_daily ADD INDEX idx_sd_date_pct (date, pct_change)",
- "ALTER TABLE stock_daily ADD INDEX idx_sd_code_date_close (code, date, close)",
+ indexes := []struct {
+ name string
+ sql string
+ }{
+ {"idx_sd_date", "ALTER TABLE stock_daily ADD INDEX idx_sd_date (date)"},
+ {"idx_sd_code_date", "ALTER TABLE stock_daily ADD INDEX idx_sd_code_date (code, date)"},
+ {"idx_sd_date_pct", "ALTER TABLE stock_daily ADD INDEX idx_sd_date_pct (date, pct_change)"},
}
for _, idx := range indexes {
- if err := db.Exec(idx).Error; err == nil {
- fmt.Printf("index created: %s\n", idx)
+ var cnt int64
+ db.Raw("SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'stock_daily' AND index_name = ?", idx.name).Scan(&cnt)
+ if cnt == 0 {
+ if err := db.Exec(idx.sql).Error; err == nil {
+ fmt.Printf("index created: %s\n", idx.name)
+ }
}
}
}()
diff --git a/web/src/components/IndexKlineChart.tsx b/web/src/components/IndexKlineChart.tsx
index 25cf33e..f32e57b 100644
--- a/web/src/components/IndexKlineChart.tsx
+++ b/web/src/components/IndexKlineChart.tsx
@@ -120,5 +120,5 @@ export default function IndexKlineChart({ data, title = '上证指数' }: Props)
return () => window.removeEventListener('resize', handleResize);
}, [data, title]);
- return
;
+ return ;
}
diff --git a/web/src/components/OverlayKlineChart.tsx b/web/src/components/OverlayKlineChart.tsx
index b169a3b..791acbe 100644
--- a/web/src/components/OverlayKlineChart.tsx
+++ b/web/src/components/OverlayKlineChart.tsx
@@ -81,6 +81,14 @@ export default function OverlayKlineChart({ series }: Props) {
}
const baseDates = [...dateSet].sort();
+ // 日期交集为空时无法绘制,清空图表退出
+ if (baseDates.length === 0) {
+ if (chartRef.current) {
+ chartRef.current.clear();
+ }
+ return;
+ }
+
// ── 2. 建立日期→数据的快速查找映射 ──
const dateMaps = series.map((s) => new Map(s.data.map((d) => [d.date.slice(0, 10), d])));
diff --git a/web/src/pages/ConsecutivePage.tsx b/web/src/pages/ConsecutivePage.tsx
index 887dff7..fe4f670 100644
--- a/web/src/pages/ConsecutivePage.tsx
+++ b/web/src/pages/ConsecutivePage.tsx
@@ -64,11 +64,7 @@ export default function ConsecutivePage() {
const maxStreak = data.length > 0 ? data[0].streak : 0;
return (
-
-
- 连板高度
-
-
+
今日涨停 {data.length} 只,
diff --git a/web/src/pages/Dashboard.tsx b/web/src/pages/Dashboard.tsx
index 12adba8..311f2ea 100644
--- a/web/src/pages/Dashboard.tsx
+++ b/web/src/pages/Dashboard.tsx
@@ -1,13 +1,11 @@
import { useEffect, useState } from 'react';
-import { Card, Spin, Table, Tag, Typography } from 'antd';
+import { Card, Spin, Table, Tag } from 'antd';
import {
getDashboardSummary,
type DashboardSummary,
} from '../api/dashboard';
import StatCards from '../components/StatCard';
-const { Title } = Typography;
-
const columns = [
{ title: '代码', dataIndex: 'code', key: 'code', width: 80 },
{ title: '名称', dataIndex: 'name', key: 'name', width: 100 },
@@ -55,11 +53,7 @@ export default function Dashboard() {
if (!summary) return 加载失败
;
return (
-
-
- A股市场概览
-
-
+
diff --git a/web/src/pages/High100Page.tsx b/web/src/pages/High100Page.tsx
index 2f1f906..bdad5fc 100644
--- a/web/src/pages/High100Page.tsx
+++ b/web/src/pages/High100Page.tsx
@@ -53,11 +53,7 @@ export default function High100Page() {
const limitUp = data.filter((s) => s.pct_change >= 9.5).length;
return (
-
-
- 百日新高
-
-
+
今日创150日新高 {data.length} 只
diff --git a/web/src/pages/IndexPage.tsx b/web/src/pages/IndexPage.tsx
index 419d7ff..b5ff93d 100644
--- a/web/src/pages/IndexPage.tsx
+++ b/web/src/pages/IndexPage.tsx
@@ -1,13 +1,13 @@
/**
* 指数行情页面
- * 左侧显示指数列表(上证指数、深证成指等),右侧显示选中指数的 K 线图
+ * 左侧显示指数列表,右侧显示选中指数的 K 线图,无左右留白
*/
import { useEffect, useState } from 'react';
import { Card, List, Spin, Typography } from 'antd';
import { getIndexKline, type IndexKline } from '../api/dashboard';
import IndexKlineChart from '../components/IndexKlineChart';
-const { Title, Text } = Typography;
+const { Text } = Typography;
/** 支持的指数列表 */
const INDICES = [
@@ -35,58 +35,53 @@ export default function IndexPage() {
const latest = kline.length > 0 ? kline[kline.length - 1] : null;
return (
-
-
- 指数行情
-
-
-
- {/* 左侧指数列表 */}
-
- (
- setSelected(item.code)}
- style={{
- cursor: 'pointer',
- padding: '8px 12px',
- background: item.code === selected ? '#e6f7ff' : undefined,
- borderRadius: 4,
- }}
- >
- {item.name}
-
- )}
- />
-
-
- {/* 右侧 K 线图 */}
-
i.code === selected)?.name}
+
+ {/* 左侧指数列表 */}
+
+
- {/* 最新收盘价和涨跌幅 */}
- {latest && (
-
- {latest.close.toFixed(2)}
- = 0 ? '#cf1322' : '#3f8600' }}
- >
- {latest.pct_change >= 0 ? '+' : ''}{latest.pct_change.toFixed(2)}%
-
-
+ dataSource={INDICES}
+ renderItem={(item) => (
+ setSelected(item.code)}
+ style={{
+ cursor: 'pointer',
+ padding: '8px 12px',
+ background: item.code === selected ? '#e6f7ff' : undefined,
+ borderRadius: 4,
+ }}
+ >
+ {item.name}
+
)}
- {loading ? (
-
-
-
- ) : (
-
- )}
-
-
+ />
+
+
+ {/* 右侧 K 线图 */}
+
i.code === selected)?.name}
+ size="small"
+ style={{ flex: 1, overflow: 'hidden' }}
+ >
+ {/* 最新收盘价和涨跌幅 */}
+ {latest && (
+
+ {latest.close.toFixed(2)}
+ = 0 ? '#cf1322' : '#3f8600' }}
+ >
+ {latest.pct_change >= 0 ? '+' : ''}{latest.pct_change.toFixed(2)}%
+
+
+ )}
+ {loading ? (
+
+
+
+ ) : (
+
+ )}
+
);
}
diff --git a/web/src/pages/OverlayPage.tsx b/web/src/pages/OverlayPage.tsx
index af3a5f4..f3e9ce8 100644
--- a/web/src/pages/OverlayPage.tsx
+++ b/web/src/pages/OverlayPage.tsx
@@ -39,7 +39,7 @@ export default function OverlayPage() {
try {
const res = await getStockKline(trimmed);
- if (!res.data || res.data.length === 0) {
+ if (!res || !res.data || res.data.length === 0) {
// 无数据时移除该条目
setStocks((prev) => prev.filter((s) => s.code !== trimmed));
message.error(trimmed + ' 无数据');
diff --git a/web/src/pages/TrendPage.tsx b/web/src/pages/TrendPage.tsx
index 988c781..18e0188 100644
--- a/web/src/pages/TrendPage.tsx
+++ b/web/src/pages/TrendPage.tsx
@@ -1,9 +1,8 @@
import { useEffect, useState } from 'react';
-import { Card, Segmented, Spin, Typography } from 'antd';
+import { Card, Segmented, Spin } from 'antd';
import { getDailySummary, type DailySummary } from '../api/dashboard';
import DailyChart from '../components/DailyChart';
-const { Title } = Typography;
export default function TrendPage() {
const [daily, setDaily] = useState
([]);
@@ -18,10 +17,7 @@ export default function TrendPage() {
}, [days]);
return (
-