Explorar o código

添加股票训练入口

yourname hai 7 meses
pai
achega
28107a7019

+ 10 - 9
client/stock/components/stock-chart/src/components/DrawingToolbar.tsx

@@ -1,7 +1,8 @@
 import React from 'react';
+import { ActiveType } from '../types/index.ts'
 
 interface DrawingToolbarProps {
-  onStartDrawing: (type: 'horizontal' | 'trend' | 'trendExtended') => void;
+  onStartDrawing: (type: ActiveType) => void;
   onStopDrawing: () => void;
   onClearLines: () => void;
   className?: string;
@@ -13,9 +14,9 @@ export const DrawingToolbar: React.FC<DrawingToolbarProps> = ({
   onClearLines,
   className = ''
 }: DrawingToolbarProps) => {
-  const [activeType, setActiveType] = React.useState<'horizontal' | 'trend' | 'trendExtended' | null>(null);
+  const [activeType, setActiveType] = React.useState<ActiveType | null>(null);
 
-  const handleToolClick = (type: 'horizontal' | 'trend' | 'trendExtended') => {
+  const handleToolClick = (type: ActiveType) => {
     if (activeType === type) {
       setActiveType(null);
       onStopDrawing();
@@ -34,9 +35,9 @@ export const DrawingToolbar: React.FC<DrawingToolbarProps> = ({
   return (
     <div className={`flex items-center space-x-2 ${className}`}>
       <button
-        onClick={() => handleToolClick('horizontal')}
+        onClick={() => handleToolClick(ActiveType.HORIZONTAL)}
         className={`px-3 py-1 text-sm font-medium rounded-md transition-colors
-          ${activeType === 'horizontal'
+          ${activeType === ActiveType.HORIZONTAL
             ? 'bg-blue-600 text-white'
             : 'bg-gray-700 text-gray-200 hover:bg-gray-600'
           }`}
@@ -44,9 +45,9 @@ export const DrawingToolbar: React.FC<DrawingToolbarProps> = ({
         水平线
       </button>
       <button
-        onClick={() => handleToolClick('trend')}
+        onClick={() => handleToolClick(ActiveType.TREND)}
         className={`px-3 py-1 text-sm font-medium rounded-md transition-colors
-          ${activeType === 'trend'
+          ${activeType === ActiveType.TREND
             ? 'bg-blue-600 text-white'
             : 'bg-gray-700 text-gray-200 hover:bg-gray-600'
           }`}
@@ -54,9 +55,9 @@ export const DrawingToolbar: React.FC<DrawingToolbarProps> = ({
         斜横线
       </button>
       <button
-        onClick={() => handleToolClick('trendExtended')}
+        onClick={() => handleToolClick(ActiveType.TREND_EXTENDED)}
         className={`px-3 py-1 text-sm font-medium rounded-md transition-colors
-          ${activeType === 'trendExtended'
+          ${activeType === ActiveType.TREND_EXTENDED
             ? 'bg-blue-600 text-white'
             : 'bg-gray-700 text-gray-200 hover:bg-gray-600'
           }`}

+ 3 - 3
client/stock/components/stock-chart/src/components/StockChart.tsx

@@ -2,13 +2,13 @@ import React, { useEffect, useRef, useImperativeHandle, forwardRef } from 'react
 import * as echarts from 'echarts';
 import type { EChartsType, EChartsOption } from 'echarts';
 import { StockChart as StockChartLib } from '../lib/index.ts';
-import type { StockData, DateMemo, TradeRecord } from '../types/index.ts';
+import type { StockData, DateMemo, TradeRecord, ActiveType } from '../types/index.ts';
 import { ChartDrawingTools } from '../lib/drawing/ChartDrawingTools.ts';
 
 // 将 StockChartRef 接口移到 Props 定义之前
 interface StockChartRef {
   toggleMemoVisibility: (visible: boolean) => void;
-  startDrawing: (type: 'horizontal' | 'trend') => void;
+  startDrawing: (type: ActiveType) => void;
   stopDrawing: () => void;
   clearDrawings: () => void;
 }
@@ -160,7 +160,7 @@ const StockChart = forwardRef<StockChartRef, StockChartProps>((
       });
       chartInstanceRef.current.setOption(currentOption);
     },
-    startDrawing: (type: 'horizontal' | 'trend') => {
+    startDrawing: (type: ActiveType) => {
       drawingToolsRef.current?.startDrawing(type);
     },
     stopDrawing: () => {

+ 7 - 1
client/stock/components/stock-chart/src/types/index.ts

@@ -1,4 +1,10 @@
-import type { EChartsOption, SeriesOption } from 'echarts';
+import type { SeriesOption } from 'echarts';
+
+export enum ActiveType {
+  HORIZONTAL = 'horizontal',
+  TREND = 'trend',
+  TREND_EXTENDED = 'trendExtended',
+}
 
 // 定义基础数据类型
 export interface StockData {

+ 26 - 25
client/stock/stock_app.tsx

@@ -2,21 +2,22 @@ import React, { useRef, useState, useCallback, useEffect } from 'react';
 import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
 import { StockChart, MemoToggle, TradePanel, useTradeRecords, useStockQueries, useProfitCalculator, ProfitDisplay, useStockDataFilter, DrawingToolbar } from './components/stock-chart/mod.ts';
 import type { StockChartRef } from './components/stock-chart/mod.ts';
-import { useSocketRoom, useQuestionManagement } from './hooks/useSocketClient.ts';
+// import { useSocketRoom, useQuestionManagement } from './hooks/useSocketClient.ts';
 import { useSearchParams } from 'react-router';
-import { message } from 'antd';
+// import { message } from 'antd';
+import { ActiveType } from "./components/stock-chart/src/types/index.ts";
 
 const queryClient = new QueryClient();
 
 function StockApp() {
   const chartRef = useRef<StockChartRef>(null);
-  const lastSentDateRef = useRef('');
+//   const lastSentDateRef = useRef('');
   const [searchParams] = useSearchParams();
   const codeFromUrl = searchParams.get('code');
-  const [stockCode, setStockCode] = useState(codeFromUrl);// || '001339'
-  const classroom = searchParams.get('classroom');
-  const { connected } = useSocketRoom(classroom);
-  const { sendNextQuestion } = useQuestionManagement(classroom);
+  const [stockCode, setStockCode] = useState(codeFromUrl || undefined);// || '001339'
+//   const classroom = searchParams.get('classroom');
+//   const { connected } = useSocketRoom(classroom);
+//   const { sendNextQuestion } = useQuestionManagement(classroom);
   
   const { 
     stockData: fullStockData, 
@@ -48,36 +49,36 @@ function StockApp() {
     }
   }, [moveToNextDay, updateCurrentDate]);
 
-  useEffect(() => {
-    const currentDate = profitSummary.dailyStats.date;
-    if (classroom && connected && currentDate && lastSentDateRef.current !== currentDate) {
-      lastSentDateRef.current = currentDate;
-      sendNextQuestion({
-        date: currentDate,
-        price: profitSummary.dailyStats.close
-      }).catch(() => {
-        message.error('发送题目失败');
-      });
-    }
-  }, [classroom, connected, profitSummary.dailyStats, sendNextQuestion]);
+//   useEffect(() => {
+//     const currentDate = profitSummary.dailyStats.date;
+//     if (classroom && connected && currentDate && lastSentDateRef.current !== currentDate) {
+//       lastSentDateRef.current = currentDate;
+//       sendNextQuestion({
+//         date: currentDate,
+//         price: profitSummary.dailyStats.close
+//       }).catch(() => {
+//         message.error('发送题目失败');
+//       });
+//     }
+//   }, [classroom, connected, profitSummary.dailyStats, sendNextQuestion]);
 
   const handleDayNumChange = useCallback((days: number) => {
     if (!isInitialized) {
-      initializeView(days);
+      initializeView();
     } else {
-      setDayNum(days, days);
+      setDayNum(days);
     }
   }, [isInitialized, initializeView, setDayNum]);
 
   const handleQuery = useCallback(() => {
-    if (stockCode.trim()) {
+    if (stockCode && stockCode.trim()) {
       fetchData().then(() => {
-        initializeView(120);
+        initializeView();
       });
     }
   }, [stockCode, fetchData, initializeView]);
 
-  const handleStartDrawing = useCallback((type: 'horizontal' | 'trend') => {
+  const handleStartDrawing = useCallback((type: ActiveType) => {
     chartRef.current?.startDrawing(type);
   }, []);
 
@@ -112,7 +113,7 @@ function StockApp() {
     if (codeFromUrl && codeFromUrl !== stockCode) {
       setStockCode(codeFromUrl);
       fetchData().then(() => {
-        initializeView(120);
+        initializeView();
       });
     }
   }, [codeFromUrl, stockCode, fetchData, initializeView]);

+ 2 - 2
deno.json

@@ -37,8 +37,8 @@
     "react-toastify": "https://esm.d8d.fun/react-toastify@11.0.5?dev&deps=react@19.0.0,react-dom@19.0.0",
     "aliyun-rtc-sdk":"https://esm.d8d.fun/aliyun-rtc-sdk@6.14.6?standalone",
     "decimal.js":"https://esm.d8d.fun/decimal.js@10.4.3",
-    "echarts":"https://esm.d8d.fun/echarts@5.5.1",
-    "echarts/types/src/util/types":"https://esm.d8d.fun/echarts@5.5.1/types/src/util/types"
+    "echarts":"https://esm.d8d.fun/echarts@5.6.0",
+    "echarts/types/src/util/types":"https://esm.d8d.fun/echarts@5.6.0/types/src/util/types"
   },
   "compilerOptions": {
     "lib": ["dom", "dom.iterable", "esnext", "deno.ns"]

+ 16 - 0
server/app.tsx

@@ -367,6 +367,14 @@ export default function({ apiClient, app, moduleDir }: ModuleParams) {
                 >
                   数据库迁移
                 </a>
+
+                {/* 股票训练入口按钮 */}
+                <a
+                  href="/stock"
+                  className="w-full flex justify-center py-3 px-4 border border-blue-600 rounded-md shadow-sm text-lg font-medium text-blue-600 bg-white hover:bg-blue-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
+                >
+                  进入股票训练
+                </a>
                 
               </div>
             </div>
@@ -479,6 +487,14 @@ export default function({ apiClient, app, moduleDir }: ModuleParams) {
     prodPath: "migrations/migrations_app.js"
   }, GLOBAL_CONFIG.APP_NAME))
 
+  honoApp.get('/stock/*', createHtmlWithConfig({
+    src: "https://esm.d8d.fun/xb",
+    href: "/client/stock/stock_app.tsx",
+    denoJson: "/deno.json",
+    refresh: true,
+    prodPath: "stock/stock_app.js"
+  }, GLOBAL_CONFIG.APP_NAME))
+
   const staticRoutes = serveStatic({
     root: moduleDir,
     onFound: async (path: string, c: HonoContext) => {

+ 1 - 0
版本迭代需求.md

@@ -1,4 +1,5 @@
 2025.05.15 0.1.1
+添加股票训练入口
 迁移入股票训练模块
 
 2025.05.13 0.1.0