@@ -1,12 +1,11 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import { useSearchParams } from 'react-router-dom'
|
import { useSearchParams } from 'react-router-dom'
|
||||||
import { useQuery } from '@tanstack/react-query'
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import { Activity, Lock, Search } from 'lucide-react'
|
import { Activity, Search } from 'lucide-react'
|
||||||
import { api, type IndexInstrument, type KlineRow, type MinuteKlineRow } from '@/lib/api'
|
import { api, type IndexInstrument, type KlineRow } from '@/lib/api'
|
||||||
import { QK } from '@/lib/queryKeys'
|
import { QK } from '@/lib/queryKeys'
|
||||||
import { useCapabilities } from '@/lib/useSharedQueries'
|
|
||||||
import { EChartsCandlestick, type OHLC } from '@/components/EChartsCandlestick'
|
import { EChartsCandlestick, type OHLC } from '@/components/EChartsCandlestick'
|
||||||
import { EChartsIntraday } from '@/components/EChartsIntraday'
|
|
||||||
|
|
||||||
function defaultRange() {
|
function defaultRange() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@@ -64,10 +63,6 @@ export function Indices() {
|
|||||||
const [selectedDate, setSelectedDate] = useState<string | null>(null)
|
const [selectedDate, setSelectedDate] = useState<string | null>(null)
|
||||||
const [linkedPrice, setLinkedPrice] = useState<number | null>(null)
|
const [linkedPrice, setLinkedPrice] = useState<number | null>(null)
|
||||||
|
|
||||||
// 分时数据需 Pro+ (kline.minute.batch) 能力
|
|
||||||
const caps = useCapabilities()
|
|
||||||
const hasMinuteCap = !!caps.data?.capabilities?.['kline.minute.batch']
|
|
||||||
|
|
||||||
const list = useQuery({
|
const list = useQuery({
|
||||||
queryKey: QK.indexList,
|
queryKey: QK.indexList,
|
||||||
queryFn: api.indexList,
|
queryFn: api.indexList,
|
||||||
@@ -108,23 +103,8 @@ export function Indices() {
|
|||||||
placeholderData: (prev) => prev,
|
placeholderData: (prev) => prev,
|
||||||
})
|
})
|
||||||
|
|
||||||
const minute = useQuery({
|
|
||||||
queryKey: QK.indexMinute(selectedSymbol, selectedDate ?? ''),
|
|
||||||
queryFn: () => api.indexMinute(selectedSymbol, selectedDate ?? undefined),
|
|
||||||
enabled: !!selectedSymbol && !!selectedDate && hasMinuteCap,
|
|
||||||
placeholderData: (prev) => prev,
|
|
||||||
})
|
|
||||||
|
|
||||||
const chartRows = useMemo(() => toOHLC(daily.data?.rows ?? []), [daily.data?.rows])
|
const chartRows = useMemo(() => toOHLC(daily.data?.rows ?? []), [daily.data?.rows])
|
||||||
const selectedInfo = [...topRows, ...listRows].find(r => r.symbol === selectedSymbol) || daily.data?.index_info
|
const selectedInfo = [...topRows, ...listRows].find(r => r.symbol === selectedSymbol) || daily.data?.index_info
|
||||||
const minuteRows: MinuteKlineRow[] = minute.data?.rows ?? []
|
|
||||||
const selectedIdx = selectedDate ? chartRows.findIndex(r => r.date === selectedDate) : -1
|
|
||||||
const prevClose = selectedIdx > 0
|
|
||||||
? chartRows[selectedIdx - 1].close
|
|
||||||
: chartRows.length >= 2
|
|
||||||
? chartRows[chartRows.length - 2].close
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedDate(null)
|
setSelectedDate(null)
|
||||||
setLinkedPrice(null)
|
setLinkedPrice(null)
|
||||||
@@ -221,52 +201,18 @@ export function Indices() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{chartRows.length > 0 && (
|
{chartRows.length > 0 && (
|
||||||
<div className="flex items-start gap-3">
|
<EChartsCandlestick
|
||||||
<div className="min-w-0 flex-1">
|
data={chartRows}
|
||||||
<EChartsCandlestick
|
height={620}
|
||||||
data={chartRows}
|
showMA={true}
|
||||||
height={620}
|
showInfoBar={true}
|
||||||
showMA={true}
|
showMarkers={false}
|
||||||
showInfoBar={true}
|
symbol={selectedSymbol}
|
||||||
showMarkers={false}
|
linkedPrice={linkedPrice}
|
||||||
symbol={selectedSymbol}
|
onDateClick={setSelectedDate}
|
||||||
linkedPrice={linkedPrice}
|
visibleBars={48}
|
||||||
onDateClick={setSelectedDate}
|
activeIndicators={['vol', 'macd']}
|
||||||
visibleBars={48}
|
/>
|
||||||
activeIndicators={['vol', 'macd']}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="min-w-0 flex-1 border-l border-border pl-3" style={{ height: 620 }}>
|
|
||||||
{!hasMinuteCap ? (
|
|
||||||
<div className="flex h-full flex-col items-center justify-center gap-2 text-center">
|
|
||||||
<Lock className="h-5 w-5 text-muted" />
|
|
||||||
<div className="text-xs text-secondary">分时数据权限需 Pro+</div>
|
|
||||||
<div className="text-[10px] text-muted">升级套餐后可查看指数分时走势</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{minute.isLoading && <div className="py-2 text-xs text-muted">分时加载中…</div>}
|
|
||||||
{!minute.isLoading && minuteRows.length === 0 && (
|
|
||||||
<div className="flex h-full items-center justify-center text-xs text-muted">
|
|
||||||
暂无分时数据
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{minuteRows.length > 0 && (
|
|
||||||
<EChartsIntraday
|
|
||||||
data={minuteRows}
|
|
||||||
height={620}
|
|
||||||
prevClose={prevClose}
|
|
||||||
date={selectedDate ?? undefined}
|
|
||||||
symbol={selectedSymbol}
|
|
||||||
showLimitLines={false}
|
|
||||||
showAvgLine={false}
|
|
||||||
onPriceHover={setLinkedPrice}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user