1
0

feat: 增加日线数据显示

This commit is contained in:
2025-09-16 07:49:51 +08:00
parent 596e3caa59
commit 17c96e96fc
6 changed files with 174 additions and 30 deletions

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourcePerFileMappings">
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/63824900-a456-4883-8de4-8f436cd00c71/console.sql" value="63824900-a456-4883-8de4-8f436cd00c71" />
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f7d817dc-8c9c-479f-b469-583df17cb013/console.sql" value="f7d817dc-8c9c-479f-b469-583df17cb013" />
</component>
</project>

View File

@@ -7,6 +7,8 @@ import com.lanyuanxiaoyao.leopard.server.service.StockService;
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import lombok.extern.slf4j.Slf4j;
@@ -94,11 +96,29 @@ public class StockController extends SimpleControllerSupport<Stock, Void, StockC
@GetMapping("finance/{id}/{field}")
public GlobalResponse<Map<String, Object>> financeCharts(@PathVariable("id") Long id, @PathVariable("field") String field) {
var data = stockService.findFinanceIndicatorRecent(id, 5);
return GlobalResponse.responseDetailData(
data.stream()
.map(item -> BeanUtil.getFieldValue(item, field))
.toList()
);
var xList = new ArrayList<Integer>();
var yList = new ArrayList<Object>();
for (var indicator : data) {
xList.add(indicator.getYear());
yList.add(BeanUtil.getFieldValue(indicator, field));
}
return GlobalResponse.responseMapData(Map.of(
"xList", xList, "yList", yList
));
}
@GetMapping("daily/{id}")
public GlobalResponse<Map<String, Object>> dailyCharts(@PathVariable("id") Long id) {
var data = stockService.findDailyRecent(id, 100);
var xList = new ArrayList<String>();
var yList = new ArrayList<List<Double>>();
for (var daily : data) {
xList.add(daily.getTradeDate().toString());
yList.add(List.of(daily.getOpen(), daily.getClose(), daily.getLow(), daily.getHigh()));
}
return GlobalResponse.responseMapData(Map.of(
"xList", xList, "yList", yList
));
}
@Override

View File

@@ -1,13 +0,0 @@
package com.lanyuanxiaoyao.leopard.server.service;
import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository;
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
import org.springframework.stereotype.Service;
@Service
public class DailyService extends SimpleServiceSupport<Daily> {
public DailyService(DailyRepository repository) {
super(repository);
}
}

View File

@@ -1,9 +1,13 @@
package com.lanyuanxiaoyao.leopard.server.service;
import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.core.entity.Daily_;
import com.lanyuanxiaoyao.leopard.core.entity.FinanceIndicator;
import com.lanyuanxiaoyao.leopard.core.entity.FinanceIndicator_;
import com.lanyuanxiaoyao.leopard.core.entity.QDaily;
import com.lanyuanxiaoyao.leopard.core.entity.QFinanceIndicator;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository;
import com.lanyuanxiaoyao.leopard.core.repository.FinanceIndicatorRepository;
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
@@ -23,12 +27,13 @@ import org.springframework.stereotype.Service;
public class StockService extends SimpleServiceSupport<Stock> {
private final StockRepository stockRepository;
private final FinanceIndicatorRepository financeIndicatorRepository;
private final DailyRepository dailyRepository;
public StockService(StockRepository repository, FinanceIndicatorRepository financeIndicatorRepository) {
public StockService(StockRepository repository, FinanceIndicatorRepository financeIndicatorRepository, DailyRepository dailyRepository) {
super(repository);
this.stockRepository = repository;
this.financeIndicatorRepository = financeIndicatorRepository;
this.dailyRepository = dailyRepository;
}
public Optional<FinanceIndicator> findFinanceIndicator(Long stockId, Integer year) {
@@ -46,4 +51,13 @@ public class StockService extends SimpleServiceSupport<Stock> {
Sort.by(Sort.Direction.ASC, FinanceIndicator_.YEAR)
);
}
public List<Daily> findDailyRecent(Long stockId, int days) {
var current = LocalDate.now();
return dailyRepository.findAll(
QDaily.daily.stock.id.eq(stockId)
.and(QDaily.daily.tradeDate.between(current.minusDays(days), current)),
Sort.by(Sort.Direction.ASC, Daily_.TRADE_DATE)
);
}
}

View File

@@ -28,7 +28,7 @@
</appender>
<logger name="com.zaxxer.hikari" level="ERROR"/>
<!--<logger name="org.hibernate.SQL" level="DEBUG"/>-->
<logger name="org.hibernate.SQL" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="Console"/>

View File

@@ -47,7 +47,6 @@ const financePropertyLabel = (id: string | undefined, label: string, type: Finan
tpl: label,
}
}
let current = new Date().getFullYear()
let formatter: (value: number) => string
switch (type) {
case 'PERCENTAGE':
@@ -138,13 +137,7 @@ const financePropertyLabel = (id: string | undefined, label: string, type: Finan
},
xAxis: {
type: 'category',
data: [
current - 5,
current - 4,
current - 3,
current - 2,
current - 1,
],
data: '${xList || []}',
axisLine: {
lineStyle: {
color: '#e0e0e0',
@@ -183,7 +176,7 @@ const financePropertyLabel = (id: string | undefined, label: string, type: Finan
},
series: [
{
data: '${detail || []}',
data: '${yList || []}',
type: 'line',
smooth: true,
showSymbol: true,
@@ -416,6 +409,135 @@ function StockDetail() {
],
},
{type: 'divider'},
"100天日线数据",
{
type: 'chart',
height: 800,
api: `get:${commonInfo.baseUrl}/stock/daily/${id}`,
config: {
backgroundColor: '#fff',
animation: true,
animationDuration: 1000,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
},
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderColor: '#333',
borderWidth: 1,
textStyle: {
color: '#fff',
fontSize: 12,
},
padding: 12,
formatter: function (params: any) {
const param = params[0]
const open = param.data[0]
const close = param.data[1]
const lowest = param.data[2]
const highest = param.data[3]
return [
`<div style="font-weight: bold; margin-bottom: 4px;">${param.name}</div>`,
`<div style="display: flex; justify-content: space-between; margin: 2px 0;">`,
`<span>开盘:</span>`,
`<span style="margin-left: 12px; font-weight: bold;">${open}</span>`,
`</div>`,
`<div style="display: flex; justify-content: space-between; margin: 2px 0;">`,
`<span>收盘:</span>`,
`<span style="margin-left: 12px; font-weight: bold;">${close}</span>`,
`</div>`,
`<div style="display: flex; justify-content: space-between; margin: 2px 0;">`,
`<span>最低:</span>`,
`<span style="margin-left: 12px; font-weight: bold;">${lowest}</span>`,
`</div>`,
`<div style="display: flex; justify-content: space-between; margin: 2px 0;">`,
`<span>最高:</span>`,
`<span style="margin-left: 12px; font-weight: bold;">${highest}</span>`,
`</div>`,
].join('')
},
},
grid: {
left: '10%',
right: '10%',
top: '10%',
bottom: '15%',
containLabel: true,
},
xAxis: {
data: '${xList || []}',
axisLine: {
lineStyle: {
color: '#e0e0e0',
},
},
axisLabel: {
color: '#666',
fontWeight: 'bold',
},
splitLine: {
show: false,
},
axisTick: {
show: false,
},
},
yAxis: {
scale: true,
axisLine: {
lineStyle: {
color: '#e0e0e0',
},
},
axisLabel: {
color: '#666',
fontWeight: 'bold',
formatter: function (value: number) {
return value.toFixed(0)
},
},
splitLine: {
lineStyle: {
type: 'dashed',
color: '#f0f0f0',
},
},
axisTick: {
show: false,
},
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
show: true,
type: 'slider',
top: '90%',
start: 0,
end: 100,
},
],
series: [
{
type: 'candlestick',
data: '${yList || []}',
itemStyle: {
color: '#eb5454',
color0: '#4aaa93',
borderColor: '#eb5454',
borderColor0: '#4aaa93',
borderWidth: 1,
},
},
],
},
},
],
},
],