Compare commits
8 Commits
edf320205d
...
5b08e9cc8a
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b08e9cc8a | |||
| cfc71f83a1 | |||
| 338554c523 | |||
| 5fa2a4e8e7 | |||
| eba80bd9cc | |||
| bf123a2747 | |||
| 9a021ddd9d | |||
| 23dba3eb06 |
1
.idea/data_source_mapping.xml
generated
1
.idea/data_source_mapping.xml
generated
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="DataSourcePerFileMappings">
|
<component name="DataSourcePerFileMappings">
|
||||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/a8b9cd0a-335e-42ae-991a-f2733200afbf/console.sql" value="a8b9cd0a-335e-42ae-991a-f2733200afbf" />
|
|
||||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f7d817dc-8c9c-479f-b469-583df17cb013/console.sql" value="f7d817dc-8c9c-479f-b469-583df17cb013" />
|
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f7d817dc-8c9c-479f-b469-583df17cb013/console.sql" value="f7d817dc-8c9c-479f-b469-583df17cb013" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
nohup /home/ubuntu/jdk-17.0.16+8/bin/java -jar /home/ubuntu/app/leopard-server-1.0.0.jar --spring.profiles.active=build --spring.web.resources.static-locations=file:/home/ubuntu/app/web --logging.parent=/home/ubuntu/app > /dev/null 2>&1 &
|
nohup /home/ubuntu/jdk-17.0.16+8/bin/java -jar /home/ubuntu/app/leopard-server-1.0.0.jar --spring.profiles.active=build --spring.web.resources.static-locations=file:/home/ubuntu/app/dist --logging.parent=/home/ubuntu/app > /dev/null 2>&1 &
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
package com.lanyuanxiaoyao.leopard.server.controller;
|
package com.lanyuanxiaoyao.leopard.server.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
|
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
|
||||||
|
import com.lanyuanxiaoyao.leopard.server.helper.NumberHelper;
|
||||||
import com.lanyuanxiaoyao.leopard.server.service.StockService;
|
import com.lanyuanxiaoyao.leopard.server.service.StockService;
|
||||||
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
|
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
|
||||||
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
|
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
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;
|
||||||
|
|
||||||
@@ -16,8 +22,11 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("stock")
|
@RequestMapping("stock")
|
||||||
public class StockController extends SimpleControllerSupport<Stock, Void, StockController.DetailItem, StockController.DetailItem> {
|
public class StockController extends SimpleControllerSupport<Stock, Void, StockController.DetailItem, StockController.DetailItem> {
|
||||||
public StockController(StockService service) {
|
private final StockService stockService;
|
||||||
|
|
||||||
|
public StockController(StockService service, StockService stockService) {
|
||||||
super(service);
|
super(service);
|
||||||
|
this.stockService = stockService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -25,6 +34,59 @@ public class StockController extends SimpleControllerSupport<Stock, Void, StockC
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("finance/{id}")
|
||||||
|
public GlobalResponse<FinanceItem> finance(@PathVariable("id") Long id) {
|
||||||
|
// 财报默认是上一年的
|
||||||
|
var year = LocalDate.now().minusYears(1).getYear();
|
||||||
|
var balanceSheet = stockService.findBalanceSheet(id, year);
|
||||||
|
var income = stockService.findIncome(id, year);
|
||||||
|
var cashFlow = stockService.findCashFlow(id, year);
|
||||||
|
return GlobalResponse.responseSuccess(new FinanceItem(
|
||||||
|
id,
|
||||||
|
year,
|
||||||
|
balanceSheet
|
||||||
|
.map(bs -> new BalanceSheetItem(
|
||||||
|
NumberHelper.formatFinanceDouble(bs.getTotalAssets()),
|
||||||
|
NumberHelper.formatFinanceDouble(bs.getTotalCurrentAssets()),
|
||||||
|
NumberHelper.formatFinanceDouble(bs.getTotalNonCurrentAssets()),
|
||||||
|
NumberHelper.formatFinanceDouble(bs.getTotalLiabilities()),
|
||||||
|
NumberHelper.formatFinanceDouble(bs.getTotalCurrentLiabilities()),
|
||||||
|
NumberHelper.formatFinanceDouble(bs.getTotalNonCurrentLiabilities())
|
||||||
|
))
|
||||||
|
.orElse(new BalanceSheetItem()),
|
||||||
|
income
|
||||||
|
.map(ic -> new IncomeItem(
|
||||||
|
NumberHelper.formatFinanceDouble(ic.getTotalOperatingRevenue()),
|
||||||
|
NumberHelper.formatFinanceDouble(ic.getTotalOperatingCost()),
|
||||||
|
NumberHelper.formatFinanceDouble(ic.getTotalProfit())
|
||||||
|
))
|
||||||
|
.orElse(new IncomeItem()),
|
||||||
|
cashFlow
|
||||||
|
.map(cf -> new CashFlowItem(
|
||||||
|
NumberHelper.formatFinanceDouble(cf.getNetProfit())
|
||||||
|
))
|
||||||
|
.orElse(new CashFlowItem())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private GlobalResponse<Map<String, Object>> convertFinanceChartData(List<?> data, String field) {
|
||||||
|
return GlobalResponse.responseDetailData(
|
||||||
|
data.stream()
|
||||||
|
.map(item -> BeanUtil.getFieldValue(item, field))
|
||||||
|
.toList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("finance/{id}/{type}/{field}")
|
||||||
|
public GlobalResponse<Map<String, Object>> financeCharts(@PathVariable("id") Long id, @PathVariable("type") String type, @PathVariable("field") String field) {
|
||||||
|
return switch (type) {
|
||||||
|
case "balanceSheet" -> convertFinanceChartData(stockService.findBalanceSheetRecent(id, 5), field);
|
||||||
|
case "income" -> convertFinanceChartData(stockService.findIncomeRecent(id, 5), field);
|
||||||
|
case "cashflow" -> convertFinanceChartData(stockService.findCashFlowRecent(id, 5), field);
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: " + type);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Function<Void, Stock> saveItemMapper() {
|
protected Function<Void, Stock> saveItemMapper() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
@@ -62,4 +124,57 @@ public class StockController extends SimpleControllerSupport<Stock, Void, StockC
|
|||||||
LocalDate listedDate
|
LocalDate listedDate
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record FinanceItem(
|
||||||
|
Long id,
|
||||||
|
Integer year,
|
||||||
|
BalanceSheetItem balanceSheet,
|
||||||
|
IncomeItem income,
|
||||||
|
CashFlowItem cashFlow
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record BalanceSheetItem(
|
||||||
|
String totalAssets,
|
||||||
|
String totalCurrentAssets,
|
||||||
|
String totalNonCurrentAssets,
|
||||||
|
String totalLiabilities,
|
||||||
|
String totalCurrentLiabilities,
|
||||||
|
String totalNonCurrentLiabilities
|
||||||
|
) {
|
||||||
|
public BalanceSheetItem() {
|
||||||
|
this(
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE,
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE,
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE,
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE,
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE,
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record IncomeItem(
|
||||||
|
String totalOperatingRevenue,
|
||||||
|
String totalOperatingCost,
|
||||||
|
String totalProfit
|
||||||
|
) {
|
||||||
|
public IncomeItem() {
|
||||||
|
this(
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE,
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE,
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record CashFlowItem(
|
||||||
|
String netProfit
|
||||||
|
) {
|
||||||
|
public CashFlowItem() {
|
||||||
|
this(
|
||||||
|
NumberHelper.FINANCE_NULL_DOUBLE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.lanyuanxiaoyao.leopard.server.helper;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.NumberUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lanyuanxiaoyao
|
||||||
|
* @version 20250912
|
||||||
|
*/
|
||||||
|
public class NumberHelper {
|
||||||
|
public static final String FINANCE_NULL_DOUBLE = "/";
|
||||||
|
|
||||||
|
public static String formatFinanceDouble(Double value) {
|
||||||
|
if (ObjectUtil.isNull(value)) {
|
||||||
|
return FINANCE_NULL_DOUBLE;
|
||||||
|
}
|
||||||
|
return NumberUtil.decimalFormat("#.##", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double parseDouble(String value) {
|
||||||
|
if (StrUtil.isBlank(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Double.parseDouble(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double parseDouble(String value, Function<Double, Double> ifSuccess) {
|
||||||
|
var result = parseDouble(value);
|
||||||
|
return ObjectUtil.isNull(result) ? null : ifSuccess.apply(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,25 @@
|
|||||||
package com.lanyuanxiaoyao.leopard.server.service;
|
package com.lanyuanxiaoyao.leopard.server.service;
|
||||||
|
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.BalanceSheet;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.BalanceSheet_;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.CashFlow;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.CashFlow_;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.Income;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.Income_;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.QBalanceSheet;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.QCashFlow;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.entity.QIncome;
|
||||||
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
|
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.repository.BalanceSheetRepository;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.repository.CashFlowRepository;
|
||||||
|
import com.lanyuanxiaoyao.leopard.core.repository.IncomeRepository;
|
||||||
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
|
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
|
||||||
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
|
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,13 +30,63 @@ import org.springframework.stereotype.Service;
|
|||||||
@Service
|
@Service
|
||||||
public class StockService extends SimpleServiceSupport<Stock> {
|
public class StockService extends SimpleServiceSupport<Stock> {
|
||||||
private final StockRepository stockRepository;
|
private final StockRepository stockRepository;
|
||||||
|
private final BalanceSheetRepository balanceSheetRepository;
|
||||||
|
private final IncomeRepository incomeRepository;
|
||||||
|
private final CashFlowRepository cashFlowRepository;
|
||||||
|
|
||||||
public StockService(StockRepository repository) {
|
public StockService(StockRepository repository, BalanceSheetRepository balanceSheetRepository, IncomeRepository incomeRepository, CashFlowRepository cashFlowRepository) {
|
||||||
super(repository);
|
super(repository);
|
||||||
this.stockRepository = repository;
|
this.stockRepository = repository;
|
||||||
|
this.balanceSheetRepository = balanceSheetRepository;
|
||||||
|
this.incomeRepository = incomeRepository;
|
||||||
|
this.cashFlowRepository = cashFlowRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> findDistinctIndustries() {
|
public Optional<BalanceSheet> findBalanceSheet(Long stockId, Integer year) {
|
||||||
return stockRepository.findDistinctIndustries();
|
return balanceSheetRepository.findOne(
|
||||||
|
QBalanceSheet.balanceSheet.year.eq(year)
|
||||||
|
.and(QBalanceSheet.balanceSheet.stock.id.eq(stockId))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Income> findIncome(Long stockId, Integer year) {
|
||||||
|
return incomeRepository.findOne(
|
||||||
|
QIncome.income.year.eq(year)
|
||||||
|
.and(QIncome.income.stock.id.eq(stockId))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<CashFlow> findCashFlow(Long stockId, Integer year) {
|
||||||
|
return cashFlowRepository.findOne(
|
||||||
|
QCashFlow.cashFlow.year.eq(year)
|
||||||
|
.and(QCashFlow.cashFlow.stock.id.eq(stockId))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BalanceSheet> findBalanceSheetRecent(Long stockId, int years) {
|
||||||
|
var current = LocalDate.now();
|
||||||
|
return balanceSheetRepository.findAll(
|
||||||
|
QBalanceSheet.balanceSheet.stock.id.eq(stockId)
|
||||||
|
.and(QBalanceSheet.balanceSheet.year.between(current.minusYears(years).getYear(), current.getYear())),
|
||||||
|
Sort.by(Sort.Direction.ASC, BalanceSheet_.YEAR)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Income> findIncomeRecent(Long stockId, int years) {
|
||||||
|
var current = LocalDate.now();
|
||||||
|
return incomeRepository.findAll(
|
||||||
|
QIncome.income.stock.id.eq(stockId)
|
||||||
|
.and(QIncome.income.year.between(current.minusYears(years).getYear(), current.getYear())),
|
||||||
|
Sort.by(Sort.Direction.ASC, Income_.YEAR)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CashFlow> findCashFlowRecent(Long stockId, int years) {
|
||||||
|
var current = LocalDate.now();
|
||||||
|
return cashFlowRepository.findAll(
|
||||||
|
QCashFlow.cashFlow.stock.id.eq(stockId)
|
||||||
|
.and(QCashFlow.cashFlow.year.between(current.minusYears(years).getYear(), current.getYear())),
|
||||||
|
Sort.by(Sort.Direction.ASC, CashFlow_.YEAR)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,28 @@
|
|||||||
package com.lanyuanxiaoyao.leopard.server.service.task;
|
package com.lanyuanxiaoyao.leopard.server.service.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.NumberUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.lanyuanxiaoyao.leopard.core.entity.Daily;
|
import com.lanyuanxiaoyao.leopard.core.entity.Daily;
|
||||||
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
|
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
|
||||||
import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository;
|
import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository;
|
||||||
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
|
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
|
||||||
|
import com.lanyuanxiaoyao.leopard.server.helper.NumberHelper;
|
||||||
|
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
|
||||||
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
|
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
|
||||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||||
import com.yomahub.liteflow.core.NodeComponent;
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@LiteflowComponent("update_daily")
|
@LiteflowComponent("update_daily")
|
||||||
public class UpdateDailyNode extends NodeComponent {
|
public class UpdateDailyNode extends TaskNodeComponent {
|
||||||
private final StockRepository stockRepository;
|
private final StockRepository stockRepository;
|
||||||
private final DailyRepository dailyRepository;
|
private final DailyRepository dailyRepository;
|
||||||
|
|
||||||
@@ -27,14 +30,14 @@ public class UpdateDailyNode extends NodeComponent {
|
|||||||
|
|
||||||
private final TransactionTemplate transactionTemplate;
|
private final TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
public UpdateDailyNode(StockRepository stockRepository, DailyRepository dailyRepository, TuShareService tuShareService, TransactionTemplate transactionTemplate) {
|
public UpdateDailyNode(TaskService taskService, StockRepository stockRepository, DailyRepository dailyRepository, TuShareService tuShareService, TransactionTemplate transactionTemplate) {
|
||||||
|
super(taskService);
|
||||||
this.stockRepository = stockRepository;
|
this.stockRepository = stockRepository;
|
||||||
this.dailyRepository = dailyRepository;
|
this.dailyRepository = dailyRepository;
|
||||||
this.tuShareService = tuShareService;
|
this.tuShareService = tuShareService;
|
||||||
this.transactionTemplate = transactionTemplate;
|
this.transactionTemplate = transactionTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Transactional(rollbackOn = Throwable.class)
|
|
||||||
@Override
|
@Override
|
||||||
public void process() {
|
public void process() {
|
||||||
var tradeDates = new HashSet<LocalDate>();
|
var tradeDates = new HashSet<LocalDate>();
|
||||||
@@ -50,11 +53,13 @@ public class UpdateDailyNode extends NodeComponent {
|
|||||||
var nowDate = LocalDate.now();
|
var nowDate = LocalDate.now();
|
||||||
var stocks = stockRepository.findAll();
|
var stocks = stockRepository.findAll();
|
||||||
var stocksMap = stocks.stream().collect(Collectors.toMap(Stock::getCode, stock -> stock));
|
var stocksMap = stocks.stream().collect(Collectors.toMap(Stock::getCode, stock -> stock));
|
||||||
tradeDates.stream()
|
var allTradeDates = tradeDates.stream()
|
||||||
.filter(date -> date.isBefore(nowDate) || date.isEqual(nowDate))
|
.filter(date -> date.isBefore(nowDate) || date.isEqual(nowDate))
|
||||||
.filter(date -> !existsTradeDates.contains(date))
|
.filter(date -> !existsTradeDates.contains(date))
|
||||||
.sorted()
|
.sorted()
|
||||||
.parallel()
|
.toList();
|
||||||
|
var total = new AtomicInteger(allTradeDates.size());
|
||||||
|
allTradeDates.parallelStream()
|
||||||
.forEach(tradeDate -> {
|
.forEach(tradeDate -> {
|
||||||
var factorResponse = tuShareService.factorList(tradeDate);
|
var factorResponse = tuShareService.factorList(tradeDate);
|
||||||
var factorMap = new HashMap<String, Double>();
|
var factorMap = new HashMap<String, Double>();
|
||||||
@@ -65,30 +70,27 @@ public class UpdateDailyNode extends NodeComponent {
|
|||||||
var response = tuShareService.dailyList(tradeDate);
|
var response = tuShareService.dailyList(tradeDate);
|
||||||
transactionTemplate.execute(status -> {
|
transactionTemplate.execute(status -> {
|
||||||
try {
|
try {
|
||||||
var count = 0;
|
|
||||||
for (List<String> item : response.data().items()) {
|
for (List<String> item : response.data().items()) {
|
||||||
var code = item.get(0);
|
var code = item.get(0);
|
||||||
if (stocksMap.containsKey(code)) {
|
if (stocksMap.containsKey(code)) {
|
||||||
count++;
|
|
||||||
var stock = stocksMap.get(code);
|
var stock = stocksMap.get(code);
|
||||||
var factor = factorMap.get(code);
|
var factor = factorMap.get(code);
|
||||||
var daily = new Daily();
|
var daily = new Daily();
|
||||||
daily.setTradeDate(LocalDate.parse(item.get(1), TuShareService.TRADE_FORMAT));
|
daily.setTradeDate(tradeDate);
|
||||||
daily.setOpen(item.get(2) == null ? null : Double.parseDouble(item.get(2)));
|
daily.setOpen(NumberHelper.parseDouble(item.get(2)));
|
||||||
daily.setHigh(item.get(3) == null ? null : Double.parseDouble(item.get(3)));
|
daily.setHigh(NumberUtil.parseDouble(item.get(3)));
|
||||||
daily.setLow(item.get(4) == null ? null : Double.parseDouble(item.get(4)));
|
daily.setLow(NumberUtil.parseDouble(item.get(4)));
|
||||||
daily.setClose(item.get(5) == null ? null : Double.parseDouble(item.get(5)));
|
daily.setClose(NumberUtil.parseDouble(item.get(5)));
|
||||||
daily.setPreviousClose(item.get(6) == null ? null : Double.parseDouble(item.get(6)));
|
daily.setPreviousClose(NumberUtil.parseDouble(item.get(6)));
|
||||||
daily.setPriceChangeAmount(item.get(7) == null ? null : Double.parseDouble(item.get(7)));
|
daily.setPriceChangeAmount(NumberUtil.parseDouble(item.get(7)));
|
||||||
daily.setPriceFluctuationRange(item.get(8) == null ? null : Double.parseDouble(item.get(8)));
|
daily.setPriceFluctuationRange(NumberUtil.parseDouble(item.get(8)));
|
||||||
daily.setVolume(item.get(9) == null ? null : Double.parseDouble(item.get(9)));
|
daily.setVolume(NumberUtil.parseDouble(item.get(9)));
|
||||||
daily.setTurnover(item.get(10) == null ? null : Double.parseDouble(item.get(10)) * 1000);
|
daily.setTurnover(NumberUtil.parseDouble(item.get(10)));
|
||||||
daily.setFactor(factor);
|
daily.setFactor(factor);
|
||||||
daily.setStock(stock);
|
daily.setStock(stock);
|
||||||
dailyRepository.save(daily);
|
dailyRepository.save(daily);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.info("Trade date: {} {}", tradeDate, count);
|
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
log.error("Error", exception);
|
log.error("Error", exception);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.lanyuanxiaoyao.leopard.server.service.task;
|
package com.lanyuanxiaoyao.leopard.server.service.task;
|
||||||
|
|
||||||
import cn.hutool.core.util.NumberUtil;
|
|
||||||
import com.lanyuanxiaoyao.leopard.core.entity.BalanceSheet;
|
import com.lanyuanxiaoyao.leopard.core.entity.BalanceSheet;
|
||||||
import com.lanyuanxiaoyao.leopard.core.entity.CashFlow;
|
import com.lanyuanxiaoyao.leopard.core.entity.CashFlow;
|
||||||
import com.lanyuanxiaoyao.leopard.core.entity.Income;
|
import com.lanyuanxiaoyao.leopard.core.entity.Income;
|
||||||
@@ -12,6 +11,7 @@ import com.lanyuanxiaoyao.leopard.core.repository.BalanceSheetRepository;
|
|||||||
import com.lanyuanxiaoyao.leopard.core.repository.CashFlowRepository;
|
import com.lanyuanxiaoyao.leopard.core.repository.CashFlowRepository;
|
||||||
import com.lanyuanxiaoyao.leopard.core.repository.IncomeRepository;
|
import com.lanyuanxiaoyao.leopard.core.repository.IncomeRepository;
|
||||||
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
|
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
|
||||||
|
import com.lanyuanxiaoyao.leopard.server.helper.NumberHelper;
|
||||||
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
|
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
|
||||||
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
|
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
|
||||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||||
@@ -64,32 +64,32 @@ public class UpdateFinanceNode extends TaskNodeComponent {
|
|||||||
).orElse(new Income());
|
).orElse(new Income());
|
||||||
income.setStock(stock);
|
income.setStock(stock);
|
||||||
income.setYear(year);
|
income.setYear(year);
|
||||||
income.setBasicEarningsPerShare(NumberUtil.parseDouble(item.get(1), null));
|
income.setBasicEarningsPerShare(NumberHelper.parseDouble(item.get(1)));
|
||||||
income.setDilutedEarningsPerShare(NumberUtil.parseDouble(item.get(2), null));
|
income.setDilutedEarningsPerShare(NumberHelper.parseDouble(item.get(2)));
|
||||||
income.setTotalOperatingRevenue(NumberUtil.parseDouble(item.get(3), null));
|
income.setTotalOperatingRevenue(NumberHelper.parseDouble(item.get(3)));
|
||||||
income.setOperatingRevenue(NumberUtil.parseDouble(item.get(4), null));
|
income.setOperatingRevenue(NumberHelper.parseDouble(item.get(4)));
|
||||||
income.setTotalOperatingCost(NumberUtil.parseDouble(item.get(5), null));
|
income.setTotalOperatingCost(NumberHelper.parseDouble(item.get(5)));
|
||||||
income.setOperatingCost(NumberUtil.parseDouble(item.get(6), null));
|
income.setOperatingCost(NumberHelper.parseDouble(item.get(6)));
|
||||||
income.setSellingExpense(NumberUtil.parseDouble(item.get(7), null));
|
income.setSellingExpense(NumberHelper.parseDouble(item.get(7)));
|
||||||
income.setAdministrativeExpense(NumberUtil.parseDouble(item.get(8), null));
|
income.setAdministrativeExpense(NumberHelper.parseDouble(item.get(8)));
|
||||||
income.setFinancialExpense(NumberUtil.parseDouble(item.get(9), null));
|
income.setFinancialExpense(NumberHelper.parseDouble(item.get(9)));
|
||||||
income.setOperatingExpense(NumberUtil.parseDouble(item.get(10), null));
|
income.setOperatingExpense(NumberHelper.parseDouble(item.get(10)));
|
||||||
income.setOperatingProfit(NumberUtil.parseDouble(item.get(11), null));
|
income.setOperatingProfit(NumberHelper.parseDouble(item.get(11)));
|
||||||
income.setAddNonOperatingIncome(NumberUtil.parseDouble(item.get(12), null));
|
income.setAddNonOperatingIncome(NumberHelper.parseDouble(item.get(12)));
|
||||||
income.setLessNonOperatingExpense(NumberUtil.parseDouble(item.get(13), null));
|
income.setLessNonOperatingExpense(NumberHelper.parseDouble(item.get(13)));
|
||||||
income.setTotalProfit(NumberUtil.parseDouble(item.get(14), null));
|
income.setTotalProfit(NumberHelper.parseDouble(item.get(14)));
|
||||||
income.setIncomeTaxExpense(NumberUtil.parseDouble(item.get(15), null));
|
income.setIncomeTaxExpense(NumberHelper.parseDouble(item.get(15)));
|
||||||
income.setNetProfitIncludingMinorityInterest(NumberUtil.parseDouble(item.get(16), null));
|
income.setNetProfitIncludingMinorityInterest(NumberHelper.parseDouble(item.get(16)));
|
||||||
income.setNetProfitExcludingMinorityInterest(NumberUtil.parseDouble(item.get(17), null));
|
income.setNetProfitExcludingMinorityInterest(NumberHelper.parseDouble(item.get(17)));
|
||||||
income.setComprehensiveIncomeAttributableToParent(NumberUtil.parseDouble(item.get(18), null));
|
income.setComprehensiveIncomeAttributableToParent(NumberHelper.parseDouble(item.get(18)));
|
||||||
income.setComprehensiveIncomeAttributableToMinorityShareholders(NumberUtil.parseDouble(item.get(19), null));
|
income.setComprehensiveIncomeAttributableToMinorityShareholders(NumberHelper.parseDouble(item.get(19)));
|
||||||
income.setEarningsBeforeInterestAndTax(NumberUtil.parseDouble(item.get(20), null));
|
income.setEarningsBeforeInterestAndTax(NumberHelper.parseDouble(item.get(20)));
|
||||||
income.setBeginningUndistributedProfit(NumberUtil.parseDouble(item.get(21), null));
|
income.setBeginningUndistributedProfit(NumberHelper.parseDouble(item.get(21)));
|
||||||
income.setDistributableProfit(NumberUtil.parseDouble(item.get(22), null));
|
income.setDistributableProfit(NumberHelper.parseDouble(item.get(22)));
|
||||||
income.setResearchAndDevelopmentExpense(NumberUtil.parseDouble(item.get(23), null));
|
income.setResearchAndDevelopmentExpense(NumberHelper.parseDouble(item.get(23)));
|
||||||
income.setFinancialExpenseInterestExpense(NumberUtil.parseDouble(item.get(24), null));
|
income.setFinancialExpenseInterestExpense(NumberHelper.parseDouble(item.get(24)));
|
||||||
income.setNetProfitFromContinuingOperations(NumberUtil.parseDouble(item.get(25), null));
|
income.setNetProfitFromContinuingOperations(NumberHelper.parseDouble(item.get(25)));
|
||||||
income.setNetProfitFromDiscontinuedOperations(NumberUtil.parseDouble(item.get(26), null));
|
income.setNetProfitFromDiscontinuedOperations(NumberHelper.parseDouble(item.get(26)));
|
||||||
incomeRepository.save(income);
|
incomeRepository.save(income);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,36 +106,36 @@ public class UpdateFinanceNode extends TaskNodeComponent {
|
|||||||
).orElse(new BalanceSheet());
|
).orElse(new BalanceSheet());
|
||||||
balanceSheet.setStock(stock);
|
balanceSheet.setStock(stock);
|
||||||
balanceSheet.setYear(year);
|
balanceSheet.setYear(year);
|
||||||
balanceSheet.setEndingTotalShares(NumberUtil.parseDouble(item.get(1), null));
|
balanceSheet.setEndingTotalShares(NumberHelper.parseDouble(item.get(1)));
|
||||||
balanceSheet.setCapitalSurplus(NumberUtil.parseDouble(item.get(2), null));
|
balanceSheet.setCapitalSurplus(NumberHelper.parseDouble(item.get(2)));
|
||||||
balanceSheet.setUndistributedProfit(NumberUtil.parseDouble(item.get(3), null));
|
balanceSheet.setUndistributedProfit(NumberHelper.parseDouble(item.get(3)));
|
||||||
balanceSheet.setMonetaryFunds(NumberUtil.parseDouble(item.get(4), null));
|
balanceSheet.setMonetaryFunds(NumberHelper.parseDouble(item.get(4)));
|
||||||
balanceSheet.setAccountsReceivable(NumberUtil.parseDouble(item.get(5), null));
|
balanceSheet.setAccountsReceivable(NumberHelper.parseDouble(item.get(5)));
|
||||||
balanceSheet.setInventories(NumberUtil.parseDouble(item.get(6), null));
|
balanceSheet.setInventories(NumberHelper.parseDouble(item.get(6)));
|
||||||
balanceSheet.setTotalCurrentAssets(NumberUtil.parseDouble(item.get(7), null));
|
balanceSheet.setTotalCurrentAssets(NumberHelper.parseDouble(item.get(7)));
|
||||||
balanceSheet.setLongTermEquityInvestments(NumberUtil.parseDouble(item.get(8), null));
|
balanceSheet.setLongTermEquityInvestments(NumberHelper.parseDouble(item.get(8)));
|
||||||
balanceSheet.setLongTermReceivables(NumberUtil.parseDouble(item.get(9), null));
|
balanceSheet.setLongTermReceivables(NumberHelper.parseDouble(item.get(9)));
|
||||||
balanceSheet.setFixedAssets(NumberUtil.parseDouble(item.get(10), null));
|
balanceSheet.setFixedAssets(NumberHelper.parseDouble(item.get(10)));
|
||||||
balanceSheet.setResearchAndDevelopmentExpenditures(NumberUtil.parseDouble(item.get(11), null));
|
balanceSheet.setResearchAndDevelopmentExpenditures(NumberHelper.parseDouble(item.get(11)));
|
||||||
balanceSheet.setGoodwill(NumberUtil.parseDouble(item.get(12), null));
|
balanceSheet.setGoodwill(NumberHelper.parseDouble(item.get(12)));
|
||||||
balanceSheet.setTotalNonCurrentAssets(NumberUtil.parseDouble(item.get(13), null));
|
balanceSheet.setTotalNonCurrentAssets(NumberHelper.parseDouble(item.get(13)));
|
||||||
balanceSheet.setTotalAssets(NumberUtil.parseDouble(item.get(14), null));
|
balanceSheet.setTotalAssets(NumberHelper.parseDouble(item.get(14)));
|
||||||
balanceSheet.setLongTermBorrowings(NumberUtil.parseDouble(item.get(15), null));
|
balanceSheet.setLongTermBorrowings(NumberHelper.parseDouble(item.get(15)));
|
||||||
balanceSheet.setShortTermBorrowings(NumberUtil.parseDouble(item.get(16), null));
|
balanceSheet.setShortTermBorrowings(NumberHelper.parseDouble(item.get(16)));
|
||||||
balanceSheet.setAccountsPayable(NumberUtil.parseDouble(item.get(17), null));
|
balanceSheet.setAccountsPayable(NumberHelper.parseDouble(item.get(17)));
|
||||||
balanceSheet.setAdvancesReceived(NumberUtil.parseDouble(item.get(18), null));
|
balanceSheet.setAdvancesReceived(NumberHelper.parseDouble(item.get(18)));
|
||||||
balanceSheet.setTotalCurrentLiabilities(NumberUtil.parseDouble(item.get(19), null));
|
balanceSheet.setTotalCurrentLiabilities(NumberHelper.parseDouble(item.get(19)));
|
||||||
balanceSheet.setTotalNonCurrentLiabilities(NumberUtil.parseDouble(item.get(20), null));
|
balanceSheet.setTotalNonCurrentLiabilities(NumberHelper.parseDouble(item.get(20)));
|
||||||
balanceSheet.setTotalLiabilities(NumberUtil.parseDouble(item.get(21), null));
|
balanceSheet.setTotalLiabilities(NumberHelper.parseDouble(item.get(21)));
|
||||||
balanceSheet.setTotalShareholdersEquityExcludingMinorityInterest(NumberUtil.parseDouble(item.get(22), null));
|
balanceSheet.setTotalShareholdersEquityExcludingMinorityInterest(NumberHelper.parseDouble(item.get(22)));
|
||||||
balanceSheet.setTotalShareholdersEquityIncludingMinorityInterest(NumberUtil.parseDouble(item.get(23), null));
|
balanceSheet.setTotalShareholdersEquityIncludingMinorityInterest(NumberHelper.parseDouble(item.get(23)));
|
||||||
balanceSheet.setTotalLiabilitiesAndShareholdersEquity(NumberUtil.parseDouble(item.get(24), null));
|
balanceSheet.setTotalLiabilitiesAndShareholdersEquity(NumberHelper.parseDouble(item.get(24)));
|
||||||
balanceSheet.setAccountsReceivable(NumberUtil.parseDouble(item.get(25), null));
|
balanceSheet.setAccountsReceivable(NumberHelper.parseDouble(item.get(25)));
|
||||||
balanceSheet.setPayables(NumberUtil.parseDouble(item.get(26), null));
|
balanceSheet.setPayables(NumberHelper.parseDouble(item.get(26)));
|
||||||
balanceSheet.setNotesAndAccountsReceivable(NumberUtil.parseDouble(item.get(27), null));
|
balanceSheet.setNotesAndAccountsReceivable(NumberHelper.parseDouble(item.get(27)));
|
||||||
balanceSheet.setNotesAndAccountsPayable(NumberUtil.parseDouble(item.get(28), null));
|
balanceSheet.setNotesAndAccountsPayable(NumberHelper.parseDouble(item.get(28)));
|
||||||
balanceSheet.setOtherReceivablesTotal(NumberUtil.parseDouble(item.get(29), null));
|
balanceSheet.setOtherReceivablesTotal(NumberHelper.parseDouble(item.get(29)));
|
||||||
balanceSheet.setFixedAssetsTotal(NumberUtil.parseDouble(item.get(30), null));
|
balanceSheet.setFixedAssetsTotal(NumberHelper.parseDouble(item.get(30)));
|
||||||
balanceSheetRepository.save(balanceSheet);
|
balanceSheetRepository.save(balanceSheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,21 +150,21 @@ public class UpdateFinanceNode extends TaskNodeComponent {
|
|||||||
QCashFlow.cashFlow.year.eq(year)
|
QCashFlow.cashFlow.year.eq(year)
|
||||||
.and(QCashFlow.cashFlow.stock.code.eq(stock.getCode()))
|
.and(QCashFlow.cashFlow.stock.code.eq(stock.getCode()))
|
||||||
).orElse(new CashFlow());
|
).orElse(new CashFlow());
|
||||||
NumberUtil.parseDouble(item.get(1), null);
|
NumberHelper.parseDouble(item.get(1));
|
||||||
cashFlow.setStock(stock);
|
cashFlow.setStock(stock);
|
||||||
cashFlow.setYear(year);
|
cashFlow.setYear(year);
|
||||||
cashFlow.setNetProfit(NumberUtil.parseDouble(item.get(1), null));
|
cashFlow.setNetProfit(NumberHelper.parseDouble(item.get(1)));
|
||||||
cashFlow.setFinancialExpense(NumberUtil.parseDouble(item.get(2), null));
|
cashFlow.setFinancialExpense(NumberHelper.parseDouble(item.get(2)));
|
||||||
cashFlow.setCashReceivedFromSalesAndServices(NumberUtil.parseDouble(item.get(3), null));
|
cashFlow.setCashReceivedFromSalesAndServices(NumberHelper.parseDouble(item.get(3)));
|
||||||
cashFlow.setSubtotalOfCashInflowsFromOperatingActivities(NumberUtil.parseDouble(item.get(4), null));
|
cashFlow.setSubtotalOfCashInflowsFromOperatingActivities(NumberHelper.parseDouble(item.get(4)));
|
||||||
cashFlow.setCashPaidToAndForEmployees(NumberUtil.parseDouble(item.get(5), null));
|
cashFlow.setCashPaidToAndForEmployees(NumberHelper.parseDouble(item.get(5)));
|
||||||
cashFlow.setCashPaidForVariousTaxes(NumberUtil.parseDouble(item.get(6), null));
|
cashFlow.setCashPaidForVariousTaxes(NumberHelper.parseDouble(item.get(6)));
|
||||||
cashFlow.setNetCashFlowFromOperatingActivities(NumberUtil.parseDouble(item.get(7), null));
|
cashFlow.setNetCashFlowFromOperatingActivities(NumberHelper.parseDouble(item.get(7)));
|
||||||
cashFlow.setSubtotalOfCashInflowsFromInvestingActivities(NumberUtil.parseDouble(item.get(8), null));
|
cashFlow.setSubtotalOfCashInflowsFromInvestingActivities(NumberHelper.parseDouble(item.get(8)));
|
||||||
cashFlow.setCashPaidForLongTermAssets(NumberUtil.parseDouble(item.get(9), null));
|
cashFlow.setCashPaidForLongTermAssets(NumberHelper.parseDouble(item.get(9)));
|
||||||
cashFlow.setSubtotalOfCashOutflowsFromInvestingActivities(NumberUtil.parseDouble(item.get(10), null));
|
cashFlow.setSubtotalOfCashOutflowsFromInvestingActivities(NumberHelper.parseDouble(item.get(10)));
|
||||||
cashFlow.setSubtotalOfCashOutflowsFromFinancingActivities(NumberUtil.parseDouble(item.get(11), null));
|
cashFlow.setSubtotalOfCashOutflowsFromFinancingActivities(NumberHelper.parseDouble(item.get(11)));
|
||||||
cashFlow.setBeginningBalanceOfCashAndCashEquivalents(NumberUtil.parseDouble(item.get(12), null));
|
cashFlow.setBeginningBalanceOfCashAndCashEquivalents(NumberHelper.parseDouble(item.get(12)));
|
||||||
cashFlowRepository.save(cashFlow);
|
cashFlowRepository.save(cashFlow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,12 @@
|
|||||||
<logger name="com.zaxxer.hikari" level="ERROR"/>
|
<logger name="com.zaxxer.hikari" level="ERROR"/>
|
||||||
<!--<logger name="org.hibernate.SQL" level="DEBUG"/>-->
|
<!--<logger name="org.hibernate.SQL" level="DEBUG"/>-->
|
||||||
|
|
||||||
<root level="INFO">
|
<springProfile name="build">
|
||||||
<appender-ref ref="Console"/>
|
<appender-ref ref="Console"/>
|
||||||
<appender-ref ref="RollingFile"/>
|
<appender-ref ref="RollingFile"/>
|
||||||
|
</springProfile>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="Console"/>
|
||||||
</root>
|
</root>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -13,6 +13,7 @@ import TaskTemplateSave from './pages/task/TaskTemplateSave.tsx'
|
|||||||
import TaskScheduleList from './pages/task/TaskScheduleList.tsx'
|
import TaskScheduleList from './pages/task/TaskScheduleList.tsx'
|
||||||
import TaskScheduleSave from './pages/task/TaskScheduleSave.tsx'
|
import TaskScheduleSave from './pages/task/TaskScheduleSave.tsx'
|
||||||
import StockCollectionList from './pages/stock/StockCollectionList.tsx'
|
import StockCollectionList from './pages/stock/StockCollectionList.tsx'
|
||||||
|
import TaskDetail from './pages/task/TaskDetail.tsx'
|
||||||
|
|
||||||
const routes: RouteObject[] = [
|
const routes: RouteObject[] = [
|
||||||
{
|
{
|
||||||
@@ -56,6 +57,10 @@ const routes: RouteObject[] = [
|
|||||||
path: 'list',
|
path: 'list',
|
||||||
Component: TaskList,
|
Component: TaskList,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'detail/:id',
|
||||||
|
Component: TaskDetail,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'template',
|
path: 'template',
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -1,6 +1,170 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {useParams} from 'react-router'
|
import {useParams} from 'react-router'
|
||||||
import {amisRender, commonInfo, remoteMappings} from '../../util/amis.tsx'
|
import {amisRender, commonInfo, readOnlyDialogOptions, remoteMappings} from '../../util/amis.tsx'
|
||||||
|
import type {Schema} from 'amis'
|
||||||
|
|
||||||
|
// 格式化财务数字显示的公共函数
|
||||||
|
const formatFinanceNumber = (value: number): string => {
|
||||||
|
if (value >= 100000000) {
|
||||||
|
return (value / 100000000).toFixed(2) + '亿'
|
||||||
|
} else if (value >= 10000) {
|
||||||
|
return (value / 10000).toFixed(2) + '万'
|
||||||
|
} else {
|
||||||
|
return value.toLocaleString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const financePropertyLabel = (id: string | undefined, label: string, type: string, field: string): Schema => {
|
||||||
|
if (!id) {
|
||||||
|
return {
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: label,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let current = new Date().getFullYear()
|
||||||
|
return {
|
||||||
|
type: 'wrapper',
|
||||||
|
size: 'none',
|
||||||
|
body: [
|
||||||
|
label,
|
||||||
|
{
|
||||||
|
className: 'ml-1 text-secondary',
|
||||||
|
type: 'action',
|
||||||
|
label: '',
|
||||||
|
icon: 'fa fa-eye',
|
||||||
|
level: 'link',
|
||||||
|
size: 'xs',
|
||||||
|
tooltip: '查看五年趋势',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: `${label}五年趋势`,
|
||||||
|
size: 'md',
|
||||||
|
bodyClassName: 'p-0',
|
||||||
|
...readOnlyDialogOptions(),
|
||||||
|
body: {
|
||||||
|
type: 'chart',
|
||||||
|
api: `get:${commonInfo.baseUrl}/stock/finance/${id}/${type}/${field}`,
|
||||||
|
height: 500,
|
||||||
|
config: {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.9)',
|
||||||
|
borderColor: '#ccc',
|
||||||
|
borderWidth: 1,
|
||||||
|
textStyle: {
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
padding: [10, 15],
|
||||||
|
formatter: (params: any) => {
|
||||||
|
const item = params[0]
|
||||||
|
return `${item.name}<br/>${item.marker}${formatFinanceNumber(item.value)}`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '5%',
|
||||||
|
right: '5%',
|
||||||
|
top: '10%',
|
||||||
|
bottom: '15%',
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: [
|
||||||
|
current - 5,
|
||||||
|
current - 4,
|
||||||
|
current - 3,
|
||||||
|
current - 2,
|
||||||
|
current - 1,
|
||||||
|
],
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#e0e0e0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#666',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
show: true,
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed',
|
||||||
|
color: '#f0f0f0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#999',
|
||||||
|
fontSize: 12,
|
||||||
|
formatter: (value: number) => {
|
||||||
|
return formatFinanceNumber(value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: '${detail || []}',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
showSymbol: true,
|
||||||
|
symbolSize: 6,
|
||||||
|
lineStyle: {
|
||||||
|
width: 3,
|
||||||
|
color: '#4096ff',
|
||||||
|
shadowColor: 'rgba(64, 150, 255, 0.3)',
|
||||||
|
shadowBlur: 5,
|
||||||
|
shadowOffsetY: 2,
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#4096ff',
|
||||||
|
borderWidth: 2,
|
||||||
|
borderColor: '#fff',
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: {
|
||||||
|
type: 'linear',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
x2: 0,
|
||||||
|
y2: 1,
|
||||||
|
colorStops: [{
|
||||||
|
offset: 0, color: 'rgba(64, 150, 255, 0.2)',
|
||||||
|
}, {
|
||||||
|
offset: 1, color: 'rgba(64, 150, 255, 0.01)',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'top',
|
||||||
|
color: '#333',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
fontSize: 12,
|
||||||
|
formatter: (params: any) => {
|
||||||
|
return formatFinanceNumber(params.value)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function StockDetail() {
|
function StockDetail() {
|
||||||
const {id} = useParams()
|
const {id} = useParams()
|
||||||
@@ -26,9 +190,78 @@ function StockDetail() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{label: '行业', content: '${industry}'},
|
{label: '行业', content: '${industry}'},
|
||||||
|
{label: '上市日期', content: '${listedDate}'},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{type: 'divider'},
|
{type: 'divider'},
|
||||||
|
{
|
||||||
|
type: 'service',
|
||||||
|
api: `get:${commonInfo.baseUrl}/stock/finance/${id}`,
|
||||||
|
body: [
|
||||||
|
'资产负债表',
|
||||||
|
{
|
||||||
|
className: 'my-2',
|
||||||
|
type: 'property',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '总资产', 'balanceSheet', 'totalAssets'),
|
||||||
|
content: '${balanceSheet.totalAssets}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '流动资产', 'balanceSheet', 'totalCurrentAssets'),
|
||||||
|
content: '${balanceSheet.totalCurrentAssets}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '非流动资产', 'balanceSheet', 'totalNonCurrentAssets'),
|
||||||
|
content: '${balanceSheet.totalNonCurrentAssets}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '总负债', 'balanceSheet', 'totalLiabilities'),
|
||||||
|
content: '${balanceSheet.totalLiabilities}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '流动负债', 'balanceSheet', 'totalCurrentLiabilities'),
|
||||||
|
content: '${balanceSheet.totalCurrentLiabilities}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '非流动负债', 'balanceSheet', 'totalNonCurrentLiabilities'),
|
||||||
|
content: '${balanceSheet.totalNonCurrentLiabilities}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'利润表',
|
||||||
|
{
|
||||||
|
className: 'my-2',
|
||||||
|
type: 'property',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '营业总收入', 'income', 'totalOperatingRevenue'),
|
||||||
|
content: '${income.totalOperatingRevenue}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '营业总成本', 'income', 'totalOperatingCost'),
|
||||||
|
content: '${income.totalOperatingCost}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '营业总利润', 'income', 'totalProfit'),
|
||||||
|
content: '${income.totalProfit}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'现金流量表',
|
||||||
|
{
|
||||||
|
className: 'my-2',
|
||||||
|
type: 'property',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: financePropertyLabel(id, '净利润', 'cashflow', 'netProfit'),
|
||||||
|
content: '${cashFlow.netProfit}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{type: 'divider'},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
|
|||||||
72
leopard-web/src/pages/task/TaskDetail.tsx
Normal file
72
leopard-web/src/pages/task/TaskDetail.tsx
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {useParams} from 'react-router'
|
||||||
|
import {amisRender, commonInfo, remoteMappings, time} from '../../util/amis.tsx'
|
||||||
|
|
||||||
|
function TaskDetail() {
|
||||||
|
const {id} = useParams()
|
||||||
|
return (
|
||||||
|
<div className="task-detail">
|
||||||
|
{amisRender(
|
||||||
|
{
|
||||||
|
type: 'page',
|
||||||
|
title: '任务详情',
|
||||||
|
initApi: `get:${commonInfo.baseUrl}/task/detail/${id}`,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'property',
|
||||||
|
items: [
|
||||||
|
{label: '名称', content: '${name}'},
|
||||||
|
{label: '描述', content: '${description}', span: 2},
|
||||||
|
{
|
||||||
|
label: '状态',
|
||||||
|
content: {
|
||||||
|
value: '${status}',
|
||||||
|
...remoteMappings('task_status', 'status'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '进度',
|
||||||
|
content: {
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: "${step}%",
|
||||||
|
},
|
||||||
|
span: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '耗时',
|
||||||
|
content: {
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: "${IF(costText, costText, '/')}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{label: '启动时间', content: time('launchedTime')},
|
||||||
|
{label: '结束时间', content: time('finishedTime')},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{type: 'divider'},
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
visibleOn: 'error',
|
||||||
|
type: 'editor',
|
||||||
|
name: 'error',
|
||||||
|
label: '错误信息',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
visibleOn: 'result',
|
||||||
|
type: 'editor',
|
||||||
|
name: 'result',
|
||||||
|
label: '结果',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(TaskDetail)
|
||||||
@@ -23,6 +23,7 @@ function TaskList() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
interval: 30000,
|
||||||
...crudCommonOptions(),
|
...crudCommonOptions(),
|
||||||
...paginationTemplate(15),
|
...paginationTemplate(15),
|
||||||
columns: [
|
columns: [
|
||||||
@@ -38,6 +39,7 @@ function TaskList() {
|
|||||||
{
|
{
|
||||||
name: 'status',
|
name: 'status',
|
||||||
label: '状态',
|
label: '状态',
|
||||||
|
align: 'center',
|
||||||
width: 100,
|
width: 100,
|
||||||
...remoteMappings('task_status', 'status'),
|
...remoteMappings('task_status', 'status'),
|
||||||
},
|
},
|
||||||
@@ -45,7 +47,7 @@ function TaskList() {
|
|||||||
name: 'step',
|
name: 'step',
|
||||||
label: '进度',
|
label: '进度',
|
||||||
type: 'progress',
|
type: 'progress',
|
||||||
showLabel: false,
|
width: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '耗时',
|
label: '耗时',
|
||||||
@@ -91,6 +93,16 @@ function TaskList() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
className: 'text-danger btn-deleted',
|
||||||
|
type: 'action',
|
||||||
|
label: '删除',
|
||||||
|
level: 'link',
|
||||||
|
actionType: 'ajax',
|
||||||
|
api: `get:${commonInfo.baseUrl}/task/remove/\${id}`,
|
||||||
|
confirmText: '确认删除任务记录<span class="text-lg font-bold mx-2">${name}</span>?',
|
||||||
|
confirmTitle: '删除',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ function TaskScheduleList() {
|
|||||||
confirmTitle: '恢复',
|
confirmTitle: '恢复',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
className: 'text-danger',
|
className: 'text-danger btn-deleted',
|
||||||
type: 'action',
|
type: 'action',
|
||||||
label: '删除',
|
label: '删除',
|
||||||
level: 'link',
|
level: 'link',
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ function TaskTemplateList() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
className: 'text-danger',
|
className: 'text-danger btn-deleted',
|
||||||
type: 'action',
|
type: 'action',
|
||||||
label: '删除',
|
label: '删除',
|
||||||
level: 'link',
|
level: 'link',
|
||||||
|
|||||||
Reference in New Issue
Block a user