feat: 股票集中显示股票对应的得分
This commit is contained in:
@@ -2,10 +2,11 @@ package com.lanyuanxiaoyao.leopard.core.entity;
|
|||||||
|
|
||||||
import com.lanyuanxiaoyao.leopard.core.Constants;
|
import com.lanyuanxiaoyao.leopard.core.Constants;
|
||||||
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
|
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.EntityListeners;
|
import jakarta.persistence.EntityListeners;
|
||||||
import jakarta.persistence.ManyToMany;
|
import jakarta.persistence.OneToMany;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -31,7 +32,7 @@ public class StockCollection extends SimpleEntity {
|
|||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@ManyToMany
|
@OneToMany(cascade = CascadeType.ALL)
|
||||||
@ToString.Exclude
|
@ToString.Exclude
|
||||||
private Set<Stock> stocks;
|
private Set<StockScore> scores;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.lanyuanxiaoyao.leopard.core.entity;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.Constants;
|
||||||
|
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.EntityListeners;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldNameConstants;
|
||||||
|
import org.hibernate.annotations.DynamicInsert;
|
||||||
|
import org.hibernate.annotations.DynamicUpdate;
|
||||||
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@FieldNameConstants
|
||||||
|
@Entity
|
||||||
|
@DynamicUpdate
|
||||||
|
@DynamicInsert
|
||||||
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
|
@Table(name = Constants.DATABASE_PREFIX + "stock_score")
|
||||||
|
public class StockScore extends SimpleEntity {
|
||||||
|
@ManyToOne
|
||||||
|
private Stock stock;
|
||||||
|
@ManyToOne
|
||||||
|
private StockCollection collection;
|
||||||
|
private Double score;
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.lanyuanxiaoyao.leopard.core.task;
|
package com.lanyuanxiaoyao.leopard.core.task;
|
||||||
|
|
||||||
import com.lanyuanxiaoyao.leopard.core.entity.StockCollection;
|
import com.lanyuanxiaoyao.leopard.core.entity.StockCollection;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.StockScore;
|
||||||
import com.lanyuanxiaoyao.leopard.core.repository.StockCollectionRepository;
|
import com.lanyuanxiaoyao.leopard.core.repository.StockCollectionRepository;
|
||||||
import com.lanyuanxiaoyao.leopard.core.service.selector.PyramidStockSelector;
|
import com.lanyuanxiaoyao.leopard.core.service.selector.PyramidStockSelector;
|
||||||
import com.lanyuanxiaoyao.leopard.core.service.selector.StockSelector;
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -33,13 +33,23 @@ public class PyramidSelect extends TaskRunner {
|
|||||||
|
|
||||||
@Transactional(rollbackFor = Throwable.class)
|
@Transactional(rollbackFor = Throwable.class)
|
||||||
@Override
|
@Override
|
||||||
public String process(Map<String, Object> params, StepUpdater updater) throws Exception {
|
public String process(Map<String, Object> params, StepUpdater updater) {
|
||||||
var candidates = pyramidStockSelector.select(new PyramidStockSelector.Request(LocalDate.now().getYear(), 50));
|
var candidates = pyramidStockSelector.select(new PyramidStockSelector.Request(LocalDate.now().getYear(), 50));
|
||||||
|
|
||||||
var collection = new StockCollection();
|
var collection = new StockCollection();
|
||||||
collection.setName("金字塔选股");
|
collection.setName("金字塔选股");
|
||||||
collection.setDescription("金字塔选股");
|
collection.setDescription("金字塔选股");
|
||||||
collection.setStocks(candidates.stream().map(StockSelector.Candidate::stock).collect(Collectors.toSet()));
|
collection.setScores(
|
||||||
|
candidates.stream()
|
||||||
|
.map(candidate -> {
|
||||||
|
var score = new StockScore();
|
||||||
|
score.setStock(candidate.stock());
|
||||||
|
score.setScore(candidate.score());
|
||||||
|
score.setCollection(collection);
|
||||||
|
return score;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toSet())
|
||||||
|
);
|
||||||
stockCollectionRepository.save(collection);
|
stockCollectionRepository.save(collection);
|
||||||
|
|
||||||
return """
|
return """
|
||||||
|
|||||||
@@ -3,18 +3,18 @@ package com.lanyuanxiaoyao.leopard.server.controller;
|
|||||||
import com.lanyuanxiaoyao.leopard.core.entity.StockCollection;
|
import com.lanyuanxiaoyao.leopard.core.entity.StockCollection;
|
||||||
import com.lanyuanxiaoyao.leopard.core.service.StockCollectionService;
|
import com.lanyuanxiaoyao.leopard.core.service.StockCollectionService;
|
||||||
import com.lanyuanxiaoyao.leopard.core.service.StockService;
|
import com.lanyuanxiaoyao.leopard.core.service.StockService;
|
||||||
import com.lanyuanxiaoyao.leopard.server.entity.StockDetailVo;
|
import com.lanyuanxiaoyao.leopard.server.entity.StockScoreVo;
|
||||||
|
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
|
||||||
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
|
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
|
||||||
import java.util.HashSet;
|
import java.util.Comparator;
|
||||||
import java.util.Set;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("stock_collection")
|
@RequestMapping("stock_collection")
|
||||||
public class StockCollectionController extends SimpleControllerSupport<StockCollection, StockCollectionController.SaveItem, StockCollectionController.ListItem, StockCollectionController.DetailItem> {
|
public class StockCollectionController extends SimpleControllerSupport<StockCollection, Void, StockCollectionController.ListItem, StockCollectionController.DetailItem> {
|
||||||
private final StockService stockService;
|
private final StockService stockService;
|
||||||
|
|
||||||
public StockCollectionController(StockCollectionService service, StockService stockService) {
|
public StockCollectionController(StockCollectionService service, StockService stockService) {
|
||||||
@@ -23,16 +23,13 @@ public class StockCollectionController extends SimpleControllerSupport<StockColl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Function<SaveItem, StockCollection> saveItemMapper() {
|
public GlobalResponse<Long> save(Void unused) throws Exception {
|
||||||
return item -> {
|
throw new UnsupportedOperationException();
|
||||||
var collection = new StockCollection();
|
}
|
||||||
collection.setId(item.id());
|
|
||||||
collection.setName(item.name());
|
@Override
|
||||||
collection.setDescription(item.description());
|
protected Function<Void, StockCollection> saveItemMapper() {
|
||||||
var stocks = stockService.list(item.stockIds());
|
throw new UnsupportedOperationException();
|
||||||
collection.setStocks(new HashSet<>(stocks));
|
|
||||||
return collection;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -41,7 +38,7 @@ public class StockCollectionController extends SimpleControllerSupport<StockColl
|
|||||||
collection.getId(),
|
collection.getId(),
|
||||||
collection.getName(),
|
collection.getName(),
|
||||||
collection.getDescription(),
|
collection.getDescription(),
|
||||||
collection.getStocks().size()
|
collection.getScores().size()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,22 +48,15 @@ public class StockCollectionController extends SimpleControllerSupport<StockColl
|
|||||||
collection.getId(),
|
collection.getId(),
|
||||||
collection.getName(),
|
collection.getName(),
|
||||||
collection.getDescription(),
|
collection.getDescription(),
|
||||||
collection.getStocks().size(),
|
collection.getScores().size(),
|
||||||
collection.getStocks()
|
collection.getScores()
|
||||||
.stream()
|
.stream()
|
||||||
.map(StockDetailVo::of)
|
.map(StockScoreVo::of)
|
||||||
.collect(Collectors.toSet())
|
.sorted(Comparator.comparing(StockScoreVo::score).reversed())
|
||||||
|
.toList()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public record SaveItem(
|
|
||||||
Long id,
|
|
||||||
String name,
|
|
||||||
String description,
|
|
||||||
Set<Long> stockIds
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public record ListItem(
|
public record ListItem(
|
||||||
Long id,
|
Long id,
|
||||||
String name,
|
String name,
|
||||||
@@ -80,7 +70,7 @@ public class StockCollectionController extends SimpleControllerSupport<StockColl
|
|||||||
String name,
|
String name,
|
||||||
String description,
|
String description,
|
||||||
Integer count,
|
Integer count,
|
||||||
Set<StockDetailVo> stocks
|
List<StockScoreVo> scores
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.lanyuanxiaoyao.leopard.server.entity;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.StockScore;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lanyuanxiaoyao
|
||||||
|
* @version 20250917
|
||||||
|
*/
|
||||||
|
public record StockScoreVo(
|
||||||
|
Long id,
|
||||||
|
String code,
|
||||||
|
String name,
|
||||||
|
String fullname,
|
||||||
|
Stock.Market market,
|
||||||
|
String industry,
|
||||||
|
LocalDate listedDate,
|
||||||
|
Double score
|
||||||
|
) {
|
||||||
|
public static StockScoreVo of(StockScore score) {
|
||||||
|
return new StockScoreVo(
|
||||||
|
score.getStock().getId(),
|
||||||
|
score.getStock().getCode(),
|
||||||
|
score.getStock().getName(),
|
||||||
|
score.getStock().getFullname(),
|
||||||
|
score.getStock().getMarket(),
|
||||||
|
score.getStock().getIndustry(),
|
||||||
|
score.getStock().getListedDate(),
|
||||||
|
score.getScore()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,10 +15,20 @@ function StockCollectionDetail() {
|
|||||||
body: [
|
body: [
|
||||||
{
|
{
|
||||||
type: 'crud',
|
type: 'crud',
|
||||||
source: '${stocks}',
|
source: '${scores}',
|
||||||
...crudCommonOptions(),
|
...crudCommonOptions(),
|
||||||
...paginationTemplate(15, undefined, ['filter-toggler']),
|
...paginationTemplate(100, undefined, ['filter-toggler']),
|
||||||
columns: stockListColumns(navigate),
|
columns: stockListColumns(
|
||||||
|
navigate,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'score',
|
||||||
|
label: '得分',
|
||||||
|
width: 50,
|
||||||
|
align: 'center',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import '@fortawesome/fontawesome-free/css/all.min.css'
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import {isEqual} from 'es-toolkit'
|
import {isEqual} from 'es-toolkit'
|
||||||
import type {NavigateFunction} from 'react-router'
|
import type {NavigateFunction} from 'react-router'
|
||||||
|
import type {ColumnSchema} from 'amis/lib/renderers/Table2'
|
||||||
|
|
||||||
export const commonInfo = {
|
export const commonInfo = {
|
||||||
debug: isEqual(import.meta.env.MODE, 'development'),
|
debug: isEqual(import.meta.env.MODE, 'development'),
|
||||||
@@ -336,7 +337,7 @@ export function remoteMappings(name: string, field: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stockListColumns(navigate: NavigateFunction) {
|
export function stockListColumns(navigate: NavigateFunction, extraColumns: Array<ColumnSchema> = []) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: 'code',
|
name: 'code',
|
||||||
@@ -370,6 +371,7 @@ export function stockListColumns(navigate: NavigateFunction) {
|
|||||||
align: 'center',
|
align: 'center',
|
||||||
...date('listedDate'),
|
...date('listedDate'),
|
||||||
},
|
},
|
||||||
|
...extraColumns,
|
||||||
{
|
{
|
||||||
type: 'operation',
|
type: 'operation',
|
||||||
label: '操作',
|
label: '操作',
|
||||||
|
|||||||
Reference in New Issue
Block a user