指数显示

This commit is contained in:
曾志威
2026-05-10 23:21:35 +08:00
parent 9e667d47cc
commit 94a59392c9
7 changed files with 88 additions and 6 deletions
+14
View File
@@ -55,3 +55,17 @@ func (h *DashboardHandler) GetHigh100(c *gin.Context) {
}
c.JSON(http.StatusOK, gin.H{"data": data})
}
func (h *DashboardHandler) GetIndexKline(c *gin.Context) {
code := c.DefaultQuery("code", "000001")
days, _ := strconv.Atoi(c.DefaultQuery("days", "60"))
if days <= 0 || days > 365 {
days = 60
}
data, err := h.svc.GetIndexKline(code, days)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": data})
}
+11
View File
@@ -71,3 +71,14 @@ type ConsecutiveLimit struct {
Close float64 `json:"close"`
PctChange float64 `json:"pct_change"`
}
type IndexKline struct {
Date string `json:"date"`
Open float64 `json:"open"`
Close float64 `json:"close"`
High float64 `json:"high"`
Low float64 `json:"low"`
Volume float64 `json:"volume"`
Amount float64 `json:"amount"`
PctChange float64 `json:"pct_change"`
}
+11
View File
@@ -291,3 +291,14 @@ func (r *StockRepo) GetConsecutiveLimits() ([]model.ConsecutiveLimit, error) {
return result, nil
}
func (r *StockRepo) GetIndexKline(code string, days int) ([]model.IndexKline, error) {
var result []model.IndexKline
r.db.Raw(`
SELECT date, open, close, high, low, volume, amount, pct_change
FROM index_daily
WHERE code = ?
ORDER BY date ASC
`, code).Scan(&result)
return result, nil
}
+1
View File
@@ -16,6 +16,7 @@ func Setup(r *gin.Engine, dh *handler.DashboardHandler) {
api.GET("/dashboard/daily", dh.GetDailySummary)
api.GET("/dashboard/consecutive", dh.GetConsecutiveLimits)
api.GET("/dashboard/high100", dh.GetHigh100)
api.GET("/dashboard/index-kline", dh.GetIndexKline)
}
// Serve frontend static files
+31 -6
View File
@@ -13,12 +13,13 @@ type cacheEntry[T any] struct {
}
type DashboardService struct {
repo *repository.StockRepo
mu sync.RWMutex
summary *cacheEntry[*model.DashboardSummary]
daily map[int]*cacheEntry[[]model.DailySummary]
consec *cacheEntry[[]model.ConsecutiveLimit]
high100 *cacheEntry[[]model.StockRank]
repo *repository.StockRepo
mu sync.RWMutex
summary *cacheEntry[*model.DashboardSummary]
daily map[int]*cacheEntry[[]model.DailySummary]
consec *cacheEntry[[]model.ConsecutiveLimit]
high100 *cacheEntry[[]model.StockRank]
indexKline map[string]*cacheEntry[[]model.IndexKline]
}
func NewDashboardService(repo *repository.StockRepo) *DashboardService {
@@ -114,3 +115,27 @@ func (s *DashboardService) GetHigh100() ([]model.StockRank, error) {
return data, nil
}
func (s *DashboardService) GetIndexKline(code string, days int) ([]model.IndexKline, error) {
s.mu.RLock()
if e, ok := s.indexKline[code]; ok && time.Now().Before(e.expires) {
data := e.data
s.mu.RUnlock()
return data, nil
}
s.mu.RUnlock()
data, err := s.repo.GetIndexKline(code, days)
if err != nil {
return nil, err
}
s.mu.Lock()
if s.indexKline == nil {
s.indexKline = make(map[string]*cacheEntry[[]model.IndexKline])
}
s.indexKline[code] = &cacheEntry[[]model.IndexKline]{data: data, expires: time.Now().Add(cacheTTL)}
s.mu.Unlock()
return data, nil
}
+4
View File
@@ -4,6 +4,7 @@ import { BrowserRouter } from 'react-router-dom';
import zhCN from 'antd/locale/zh_CN';
import {
DashboardOutlined,
FundOutlined,
LineChartOutlined,
RiseOutlined,
ThunderboltOutlined,
@@ -12,11 +13,13 @@ import Dashboard from './pages/Dashboard';
import TrendPage from './pages/TrendPage';
import ConsecutivePage from './pages/ConsecutivePage';
import High100Page from './pages/High100Page';
import IndexPage from './pages/IndexPage';
const { Header, Content } = Layout;
const menuItems = [
{ key: '/', icon: <DashboardOutlined />, label: '市场概览' },
{ key: '/index', icon: <FundOutlined />, label: '指数行情' },
{ key: '/high100', icon: <RiseOutlined />, label: '百日新高' },
{ key: '/consecutive', icon: <ThunderboltOutlined />, label: '连板高度' },
{ key: '/trend', icon: <LineChartOutlined />, label: '每日趋势' },
@@ -44,6 +47,7 @@ function AppLayout() {
<Content style={{ padding: 16, background: '#f5f5f5', overflow: 'auto' }}>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/index" element={<IndexPage />} />
<Route path="/high100" element={<High100Page />} />
<Route path="/consecutive" element={<ConsecutivePage />} />
<Route path="/trend" element={<TrendPage />} />
+16
View File
@@ -65,3 +65,19 @@ export async function getHigh100(): Promise<StockRank[]> {
const res = await api.get('/dashboard/high100');
return res.data.data;
}
export interface IndexKline {
date: string;
open: number;
close: number;
high: number;
low: number;
volume: number;
amount: number;
pct_change: number;
}
export async function getIndexKline(code = '000001', days = 60): Promise<IndexKline[]> {
const res = await api.get('/dashboard/index-kline', { params: { code, days } });
return res.data.data;
}