Skip to content

Commit 4edd013

Browse files
feat: introduce new common UI components, enhance trade dashboard with detailed metrics, and add an onboarding tour."
1 parent 9fd7faa commit 4edd013

18 files changed

Lines changed: 1127 additions & 176 deletions

docs/plans/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ v0.4 UX 冲刺 (1.5 周)
2828

2929
| # | 计划名称 | RICE 分 | 工期 | 状态 | 文件 |
3030
|:-:|----------|:-------:|:----:|:----:|------|
31-
| 01 | 交易表单优化 | 8.00 | 2d | 🔲 待执行 | [Plan-01](./Plan-01-TradeFormEnhancements.md) |
32-
| 02 | 账户操作安全网 | 6.00 | 1d | 🔲 待执行 | [Plan-02](./Plan-02-AccountSafetyNet.md) |
33-
| 03 | UI 语言统一 | 6.67 | 3d | 🔲 待执行 | [Plan-03](./Plan-03-LanguageUnification.md) |
34-
| 04 | LIVE 模式交易提示 | 5.00 | 1d | 🔲 待执行 | [Plan-04](./Plan-04-LiveModePrompt.md) |
35-
| 05 | 新手引导流程 | 3.36 | 5d | 🔲 待执行 | [Plan-05](./Plan-05-OnboardingFlow.md) |
36-
| 06 | 风险可视化升级 | 1.92 | 3d | 🔲 待执行 | [Plan-06](./Plan-06-RiskVisualization.md) |
31+
| 01 | 交易表单优化 | 8.00 | 2d | ✅ 已完成 | [Plan-01](./Plan-01-TradeFormEnhancements.md) |
32+
| 02 | 账户操作安全网 | 6.00 | 1d | ✅ 已完成 | [Plan-02](./Plan-02-AccountSafetyNet.md) |
33+
| 03 | UI 语言统一 | 6.67 | 3d | ✅ 已完成 | [Plan-03](./Plan-03-LanguageUnification.md) |
34+
| 04 | LIVE 模式交易提示 | 5.00 | 1d | ✅ 已完成 | [Plan-04](./Plan-04-LiveModePrompt.md) |
35+
| 05 | 新手引导流程 | 3.36 | 5d | ✅ 已完成 | [Plan-05](./Plan-05-OnboardingFlow.md) |
36+
| 06 | 风险可视化升级 | 1.92 | 3d | ✅ 已完成 | [Plan-06](./Plan-06-RiskVisualization.md) |
3737

3838
---
3939

src/App.tsx

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import KLineChart, {
1414
} from './components/Dashboard/Chart';
1515
import ChartToolbar from './components/Dashboard/Chart/ChartToolbar';
1616
import DepthChart from './components/Dashboard/Chart/DepthChart';
17-
import { TradePanel } from './components/Dashboard/Trade';
17+
import { TradePanel, LiveModeNotice } from './components/Dashboard/Trade';
18+
import OnboardingTour from './components/Onboarding/OnboardingTour';
1819
import { useUiStore } from './hooks/ui/useUiStore';
1920
import type { UiState } from './hooks/ui/useUiStore';
2021
import { useMarketStats } from './hooks/useMarketStats';
@@ -158,7 +159,7 @@ function App() {
158159
} else {
159160
(navigator as any)?.vibrate?.(20);
160161
}
161-
} catch {}
162+
} catch { }
162163
}, [isSwitching]);
163164

164165
useEffect(() => {
@@ -339,10 +340,9 @@ function App() {
339340
flex flex-col
340341
md:grid md:h-full
341342
gap-px bg-border-dark
342-
${
343-
dataSource === 'mock'
344-
? 'md:grid-cols-[1fr_240px] xl:grid-cols-[1fr_240px_300px]'
345-
: 'md:grid-cols-[1fr_240px] xl:grid-cols-[1fr_auto]'
343+
${dataSource === 'mock'
344+
? 'md:grid-cols-[1fr_240px] xl:grid-cols-[1fr_240px_300px]'
345+
: 'md:grid-cols-[1fr_240px] xl:grid-cols-[1fr_auto]'
346346
}
347347
`}
348348
>
@@ -506,10 +506,9 @@ function App() {
506506
</div>
507507
</section>
508508

509-
{/* ========== 交易面板区域 (仅 MOCK 模式下显示) ========== */}
510-
{/* LIVE 模式下隐藏交易面板,只展示数据 */}
511-
{dataSource === 'mock' && (
512-
<section className="hidden xl:block h-full min-h-0 border-l border-border-dark">
509+
{/* ========== 交易面板区域 ========== */}
510+
<section className="hidden xl:block h-full min-h-0 border-l border-border-dark">
511+
{dataSource === 'mock' ? (
513512
<TradePanel
514513
symbol="BTC"
515514
currentPrice={latestData?.price ?? 40000}
@@ -528,14 +527,19 @@ function App() {
528527
onAddMargin={addMargin}
529528
onEstimateLiquidation={estimateLiquidation}
530529
/>
531-
</section>
532-
)}
530+
) : (
531+
<div className="bg-gray-900/50 rounded-xl border border-gray-800 m-2 h-[calc(100%-1rem)]">
532+
<LiveModeNotice
533+
onSwitchToMock={() => setDataSource('mock')}
534+
/>
535+
</div>
536+
)}
537+
</section>
533538
</div>
534539
</main>
535540

536-
{/* ========== 移动端 Sticky 底部交易栏 (仅 MOCK 模式下显示) ========== */}
537-
{/* TradePanel 内部已包含移动端 Bottom Sheet,此处仅渲染移动端部分 */}
538-
{dataSource === 'mock' && (
541+
{/* ========== 移动端 Sticky 底部交易栏 ========== */}
542+
{dataSource === 'mock' ? (
539543
<div className="xl:hidden">
540544
<TradePanel
541545
symbol="BTC"
@@ -556,7 +560,25 @@ function App() {
556560
onEstimateLiquidation={estimateLiquidation}
557561
/>
558562
</div>
563+
) : (
564+
<div className="xl:hidden fixed bottom-0 left-0 right-0 bg-gray-900 border-t border-gray-800 px-4 py-3 safe-area-inset-bottom">
565+
<div className="flex items-center justify-between">
566+
<div className="flex items-center gap-2">
567+
<span className="text-blue-400"></span>
568+
<span className="text-sm text-gray-400">实时行情仅供观察</span>
569+
</div>
570+
<button
571+
onClick={() => setDataSource('mock')}
572+
className="text-sm text-yellow-400 font-medium"
573+
>
574+
切换至 Mock
575+
</button>
576+
</div>
577+
</div>
559578
)}
579+
580+
{/* ========== 新手引导 (仅 Mock 模式显示) ========== */}
581+
{dataSource === 'mock' && <OnboardingTour />}
560582
</div>
561583
);
562584
}

src/components/Dashboard/StatsPanel.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { memo } from 'react';
22
import type { StatsPanelProps } from '../../types/index';
3+
import { UI_TEXT } from '../../constants/ui-glossary';
34

45
/* ============================================
56
StatCell Sub-Component (高密度信息单元)
@@ -102,7 +103,7 @@ function StatsPanel({
102103

103104
{/* Funding Rate / Countdown */}
104105
<StatCell
105-
label="Funding / Countdown"
106+
label={`${UI_TEXT.market.fundingRate} / ${UI_TEXT.market.countdown}`}
106107
value={`${((marketStats?.fundingRate ?? 0) * 100).toFixed(4)}%`}
107108
suffix={formatFundingCountdown(marketStats?.fundingCountdown ?? 0)}
108109
colorClass={(marketStats?.fundingRate ?? 0) >= 0 ? 'text-success' : 'text-danger'}
@@ -111,7 +112,7 @@ function StatsPanel({
111112

112113
{/* 24h Change */}
113114
<StatCell
114-
label="24h Change"
115+
label={UI_TEXT.market.change24h}
115116
value={`${changeSign}${changePercent.toFixed(2)}%`}
116117
suffix={`${changeSign}${(marketStats?.priceChange ?? 0).toFixed(2)}`}
117118
colorClass={changeColor}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { memo } from 'react';
2+
3+
interface LiveModeNoticeProps {
4+
onSwitchToMock?: () => void;
5+
}
6+
7+
/**
8+
* LiveModeNotice - LIVE 模式交易提示
9+
*
10+
* 在 Binance 实时行情模式下显示,提示用户切换至 Mock 模式进行模拟交易
11+
*/
12+
function LiveModeNotice({ onSwitchToMock }: LiveModeNoticeProps) {
13+
return (
14+
<div
15+
className="flex flex-col items-center justify-center h-full min-h-[300px]
16+
p-6 text-center"
17+
>
18+
{/* 图标 */}
19+
<div
20+
className="w-16 h-16 mb-4 rounded-full bg-blue-500/10
21+
flex items-center justify-center"
22+
>
23+
<svg
24+
className="w-8 h-8 text-blue-400"
25+
fill="none"
26+
viewBox="0 0 24 24"
27+
stroke="currentColor"
28+
>
29+
<path
30+
strokeLinecap="round"
31+
strokeLinejoin="round"
32+
strokeWidth={1.5}
33+
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
34+
/>
35+
</svg>
36+
</div>
37+
38+
{/* 标题 */}
39+
<h3 className="text-lg font-semibold text-white mb-2">实时行情模式</h3>
40+
41+
{/* 说明 */}
42+
<p className="text-sm text-gray-400 mb-6 max-w-xs">
43+
当前连接 Binance 实时行情,仅供观察学习。
44+
<br />
45+
如需模拟交易,请切换至 Mock 模式。
46+
</p>
47+
48+
{/* 切换按钮 */}
49+
{onSwitchToMock && (
50+
<button
51+
type="button"
52+
onClick={onSwitchToMock}
53+
className="px-6 py-2.5 text-sm font-medium text-white
54+
bg-linear-to-r from-yellow-500 to-yellow-600
55+
hover:from-yellow-400 hover:to-yellow-500
56+
rounded-lg transition-all shadow-lg shadow-yellow-500/20"
57+
>
58+
切换至 Mock 模式
59+
</button>
60+
)}
61+
62+
{/* 补充说明 */}
63+
<p className="text-xs text-gray-500 mt-4 max-w-xs">
64+
💡 Mock 模式使用模拟数据,安全无风险
65+
</p>
66+
</div>
67+
);
68+
}
69+
70+
export default memo(LiveModeNotice);

0 commit comments

Comments
 (0)