From c62f044f5d1fb5ea400b6a3584882b6b02aaff9e Mon Sep 17 00:00:00 2001 From: Lxy Date: Tue, 24 Feb 2026 00:04:46 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20k=E7=BA=BF=E5=9B=BE=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=EF=BC=9B=E5=BD=93=E5=89=8D=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E5=A4=84=E7=90=86=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=9A1=E3=80=81=E5=85=B6=E4=BB=96=E6=8A=80=E6=9C=AF?= =?UTF-8?q?=E5=86=85=E5=AE=B9=EF=BC=9B2=E3=80=81ai=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95=EF=BC=8C=E4=BC=A0=E5=85=A5=E5=A4=9A?= =?UTF-8?q?=E6=9D=A1k=E7=BA=BF=E6=95=B0=E6=8D=AE=EF=BC=9B3=E3=80=81?= =?UTF-8?q?=E5=85=B7=E4=BD=93=E5=90=88=E7=BA=A6=E4=BB=A3=E7=A0=81=E5=A6=82?= =?UTF-8?q?=E4=BD=95=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/data/futures_analysis.db | Bin 11218944 -> 11218944 bytes package-lock.json | 32 +++ package.json | 1 + src/pages/detail/Detail.jsx | 187 ++++++++++-------- 4 files changed, 133 insertions(+), 87 deletions(-) diff --git a/backend/service_implementation/service/data/futures_analysis.db b/backend/service_implementation/service/data/futures_analysis.db index b533c4c0293099a253dc7a49972426886f3216f1..c6450c5f5fd0d77340018c3347cc7c37a1e8f167 100644 GIT binary patch delta 1690 zcmZwG$#WHD6vkm=z|4t?Gtn>x71R9s>#s+qCJ_ih!XV;+DB_4i6ctn)NQ1tPC7yUkU&ex|;5B_#+>R^5ym|k<@ zV0%x^iIJ_l7Sz`Et~m7bg3g+s_9AM;*`iiV5mUuEqE6I{2GJ;*M6+lSt)fkwE6x+= zi)rElaiO?KTr4gTmx{~8bkQy@7gvZ5F+nBRpY+F9H#YNW>x$3&kR_SS%4sMJkqwZqXyI70bm6u~PJkRiaO<7T1Y2qF<~P z>%@AoL0m63iW|fxaih3N+$?Spo5ihSi?~hPF1Ct0#5QrKxJ%qE?h*Hj`^0u}zj#1A zC>|06;$iWK*dZPjkBP^{PO(coA)XXZiQVF9@r-y@JSX;uL6M2QVxM?kydWfA6fcRF z#Vg`f@tW8#UKekO1LB|<5{JZ_;w|yE7#8n{!{S}>o_Jq;AU+fyiI2r6;#2XN_*@(j zUx+WoSK{k$`DV&r-5qtO&T9Lp<)LmOomKv}|kXX#S=7aPy|-X-y}a z_BZu4)iwUum^ChG__yJ^hMf(j{?Gbj_1o(^>rRc19N+V6&FBxu_nfS{59d$%YtwAQ z@W{~C_IY+ABzOt2Ltwnv7);QG=`!97H>f0Ow*E})`ncYtcwGs1%<&T6CKks;F&-18 zUrEwzZ9%#=jG{?p|G4xL>p8LYF-2KQ(risx&d$4+WfU9h28EgxIsE(PxMQx#rJK01 zV@#O0FUV4oW~;}$m!<1_ksnSf`%X(6CMI&iIPh&;Ez3!ottv=2b|ZgM**ihHp%deW zZsDAHO*c%lmDMsb)`adEHA`~ExU`AuI)U%|6uXy_G+SPl`8;h|`XM$b)~v|kzqeH8 zX-xu-A4Q?Hh3=&!&3eYWS0u6P7vHENyH86@VvOSlCN55?oTS;Zf^b|Q1zGDq@1K#Qg$6<&I?LY Pneda3xzPdV=upjnGO67> delta 616 zcma*h#a5I706<}X%KisCz*cPLnuvvp-Q9uRV-jM_IO?^Puu<%G!EBu4!gF{8wyt#L z+Jz4wkKp2d>znxXB|FhtOl!lkqY^Cdwq4EJZR!ie;)ylj$-;W=e_7lG!pxN@cFhllihh7Rn-7 zEK6jmER*H3LRQKuSuJa1t*n#vvOzY=CfO`oWUFkG?XpA4WT)(s-Lgma%0AgI2jrj} zlEZRDj!I09$#FR$C*_o!mU5|(N~w}FQY~lYoSc^n5|@Nrl%!me%W_4Ot8z`Q%MH0H zx8%0mk-JhOwNfYba!>Bd19>QqYfoI@J{a8Kj$=;w}GSLy(RYey$7t0ULGVbpQYW diff --git a/package-lock.json b/package-lock.json index d47f332..51aced3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@reduxjs/toolkit": "^2.11.2", "antd": "^6.3.0", + "echarts": "^6.0.0", "lightweight-charts": "^5.1.0", "react": "^19.2.0", "react-dom": "^19.2.0", @@ -2211,6 +2212,22 @@ "node": ">=8" } }, + "node_modules/echarts": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz", + "integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "2.3.0", + "zrender": "6.0.0" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, "node_modules/electron-to-chromium": { "version": "1.5.286", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", @@ -3805,6 +3822,21 @@ "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } + }, + "node_modules/zrender": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-6.0.0.tgz", + "integrity": "sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg==", + "license": "BSD-3-Clause", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" } } } diff --git a/package.json b/package.json index 39d89f7..db9e214 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "dependencies": { "@reduxjs/toolkit": "^2.11.2", "antd": "^6.3.0", + "echarts": "^6.0.0", "lightweight-charts": "^5.1.0", "react": "^19.2.0", "react-dom": "^19.2.0", diff --git a/src/pages/detail/Detail.jsx b/src/pages/detail/Detail.jsx index bcbd2be..02a1435 100644 --- a/src/pages/detail/Detail.jsx +++ b/src/pages/detail/Detail.jsx @@ -1,9 +1,9 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { Card, Button, Row, Col, Select, Tabs, Tag, Statistic, Alert, Spin } from 'antd'; import { useParams, useNavigate } from 'react-router-dom'; import { LineChartOutlined, BarChartOutlined, AreaChartOutlined, ArrowUpOutlined, AlertOutlined, RobotOutlined, SafetyOutlined } from '@ant-design/icons'; import { generateFutureData, generateKlineData } from '../../utils/mockData'; -import { createChart } from 'lightweight-charts'; +import * as echarts from 'echarts'; import './Detail.css'; const { Option } = Select; @@ -52,7 +52,7 @@ const Detail = () => { // 销毁旧图表 if (chartInstance.current) { - chartInstance.current.destroy(); + chartInstance.current.dispose(); } // 从后端API获取K线数据 @@ -85,93 +85,106 @@ const Detail = () => { // 检查chartRef.current是否存在 if (!chartRef.current) return; - // 创建图表 - const chart = createChart(chartRef.current, { - width: chartRef.current.clientWidth, - height: 400, - timeScale: { - timeVisible: true, - secondsVisible: false, + // 创建ECharts实例 + const chart = echarts.init(chartRef.current); + console.log('ECharts instance created:', chart); + + // 准备K线数据 + const candlestickData = klineData.map(item => [ + new Date(item.timestamp * 1000).getTime(), // 时间戳 + item.open, // 开盘价 + item.close, // 收盘价 + item.low, // 最低价 + item.high // 最高价 + ]); + + console.log('Candlestick data for ECharts:', candlestickData); + + // 准备MA5数据 + const ma5Data = []; + for (let i = 4; i < klineData.length; i++) { + const sum = klineData.slice(i - 4, i + 1).reduce((acc, item) => acc + item.close, 0); + ma5Data.push([ + new Date(klineData[i].timestamp * 1000).getTime(), + sum / 5 + ]); + } + + // 准备MA10数据 + const ma10Data = []; + for (let i = 9; i < klineData.length; i++) { + const sum = klineData.slice(i - 9, i + 1).reduce((acc, item) => acc + item.close, 0); + ma10Data.push([ + new Date(klineData[i].timestamp * 1000).getTime(), + sum / 10 + ]); + } + + // 配置选项 + const option = { + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'cross' + } + }, + legend: { + data: ['K线', 'MA5', 'MA10'] }, grid: { - vertLines: { - color: 'rgba(42, 46, 57, 0.1)', + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis: { + type: 'time', + boundaryGap: false + }, + yAxis: { + type: 'value', + scale: true + }, + series: [ + { + name: 'K线', + type: 'candlestick', + data: candlestickData, + itemStyle: { + color: '#52c41a', + color0: '#ff4d4f', + borderColor: '#52c41a', + borderColor0: '#ff4d4f' + } }, - horzLines: { - color: 'rgba(42, 46, 57, 0.1)', + { + name: 'MA5', + type: 'line', + data: ma5Data, + smooth: true, + lineStyle: { + width: 1, + color: '#1890ff' + }, + showSymbol: false }, - }, - }); - - // 检查chart对象是否正确创建 - console.log('Chart object:', chart); - console.log('Chart methods:', Object.keys(chart)); - - // 添加K线系列 - try { - const candlestickSeries = chart.addCandlestickSeries({ - upColor: '#52c41a', - downColor: '#ff4d4f', - borderVisible: false, - wickUpColor: '#52c41a', - wickDownColor: '#ff4d4f', - }); - - // 设置K线数据 - candlestickSeries.setData(klineData.map(item => ({ - time: new Date(item.timestamp * 1000).toISOString().split('T')[0], - open: item.open, - high: item.high, - low: item.low, - close: item.close, - }))); - - // 根据当前指标添加相应的技术指标 - if (currentIndicator === 'MA') { - // 添加MA5 - const ma5Series = chart.addLineSeries({ - color: '#1890ff', - lineWidth: 1, - }); - // 计算MA5数据 - const ma5Data = []; - for (let i = 4; i < klineData.length; i++) { - const sum = klineData.slice(i - 4, i + 1).reduce((acc, item) => acc + item.close, 0); - ma5Data.push({ - time: new Date(klineData[i].timestamp * 1000).toISOString().split('T')[0], - value: sum / 5, - }); - } - ma5Series.setData(ma5Data); - - // 添加MA10 - const ma10Series = chart.addLineSeries({ - color: '#faad14', - lineWidth: 1, - }); - // 计算MA10数据 - const ma10Data = []; - for (let i = 9; i < klineData.length; i++) { - const sum = klineData.slice(i - 9, i + 1).reduce((acc, item) => acc + item.close, 0); - ma10Data.push({ - time: new Date(klineData[i].timestamp * 1000).toISOString().split('T')[0], - value: sum / 10, - }); + { + name: 'MA10', + type: 'line', + data: ma10Data, + smooth: true, + lineStyle: { + width: 1, + color: '#faad14' + }, + showSymbol: false } - ma10Series.setData(ma10Data); - } - } catch (error) { - console.error('Error creating chart series:', error); - // 失败时使用模拟数据创建简单的线图 - const lineSeries = chart.addLineSeries({ - color: '#1890ff', - lineWidth: 1, - }); - lineSeries.setData(klineData.map(item => ({ - time: new Date(item.timestamp * 1000).toISOString().split('T')[0], - value: item.close, - }))); - } + ] + }; + + // 设置配置 + chart.setOption(option); + console.log('ECharts option set successfully'); // 保存图表实例 chartInstance.current = chart; @@ -179,7 +192,7 @@ const Detail = () => { // 处理窗口大小变化 const handleResize = () => { if (chartInstance.current) { - chartInstance.current.resize(chartRef.current.clientWidth, 400); + chartInstance.current.resize(); } }; @@ -189,7 +202,7 @@ const Detail = () => { return () => { window.removeEventListener('resize', handleResize); if (chartInstance.current) { - chartInstance.current.destroy(); + chartInstance.current.dispose(); } }; });