SHA256
指数显示
This commit is contained in:
@@ -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})
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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 />} />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user