1
0

Compare commits

...

9 Commits

41 changed files with 470 additions and 154 deletions

View File

@@ -1,5 +1,11 @@
<component name="ProjectCodeStyleConfiguration"> <component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173"> <code_scheme name="Project" version="173">
<JSCodeStyleSettings version="0">
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
</JSCodeStyleSettings>
<JavaCodeStyleSettings> <JavaCodeStyleSettings>
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="100" /> <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="100" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="100" /> <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="100" />
@@ -25,7 +31,6 @@
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" /> <option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" /> <option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="USE_DOUBLE_QUOTES" value="false" /> <option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" /> <option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
</TypeScriptCodeStyleSettings> </TypeScriptCodeStyleSettings>
<codeStyleSettings language="CSS"> <codeStyleSettings language="CSS">

15
.idea/compiler.xml generated
View File

@@ -8,7 +8,7 @@
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" /> <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" /> <outputRelativeToContentRoot value="true" />
</profile> </profile>
<profile name="Annotation profile for leopard" enabled="true"> <profile name="Annotation profile for leopard-core" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" /> <sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" /> <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" /> <outputRelativeToContentRoot value="true" />
@@ -86,11 +86,18 @@
<entry name="$MAVEN_REPOSITORY$/org/objenesis/objenesis/3.4/objenesis-3.4.jar" /> <entry name="$MAVEN_REPOSITORY$/org/objenesis/objenesis/3.4/objenesis-3.4.jar" />
<entry name="$MAVEN_REPOSITORY$/org/javassist/javassist/3.30.2-GA/javassist-3.30.2-GA.jar" /> <entry name="$MAVEN_REPOSITORY$/org/javassist/javassist/3.30.2-GA/javassist-3.30.2-GA.jar" />
</processorPath> </processorPath>
<module name="leopard-core" />
</profile>
<profile name="Annotation profile for leopard" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="false">
<entry name="$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-configuration-processor/3.5.0/spring-boot-configuration-processor-3.5.0.jar" />
<entry name="$MAVEN_REPOSITORY$/org/projectlombok/lombok/1.18.38/lombok-1.18.38.jar" />
</processorPath>
<module name="leopard-server" /> <module name="leopard-server" />
</profile> </profile>
</annotationProcessing> </annotationProcessing>
<bytecodeTargetLevel>
<module name="leopard-core" target="17" />
</bytecodeTargetLevel>
</component> </component>
</project> </project>

24
.idea/dataSources.xml generated
View File

@@ -27,5 +27,29 @@
</jdbc-additional-properties> </jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir> <working-dir>$ProjectFileDir$</working-dir>
</data-source> </data-source>
<data-source source="LOCAL" name="postgres@192.168.31.127" uuid="f7d817dc-8c9c-479f-b469-583df17cb013">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://192.168.31.127:6785/postgres</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
<property name="com.intellij.clouds.kubernetes.db.container.port" />
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
<data-source source="LOCAL" name="leopard@192.168.31.127" uuid="4b5dd0f8-26c8-49e2-b794-d464461c121a">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://192.168.31.127:6785/leopard</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
<property name="com.intellij.clouds.kubernetes.db.container.port" />
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component> </component>
</project> </project>

View File

@@ -1,6 +1,8 @@
<?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/4b5dd0f8-26c8-49e2-b794-d464461c121a/console.sql" value="4b5dd0f8-26c8-49e2-b794-d464461c121a" />
<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/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" />
</component> </component>
</project> </project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/leopard-core/leopard-core.iml" filepath="$PROJECT_DIR$/leopard-core/leopard-core.iml" />
</modules>
</component>
</project>

65
leopard-core/pom.xml Normal file
View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lanyuanxiaoyao</groupId>
<artifactId>leopard</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>leopard-core</artifactId>
<dependencies>
<dependency>
<groupId>com.lanyuanxiaoyao</groupId>
<artifactId>spring-boot-service-template</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
<path>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>6.6.8.Final</version>
</path>
<path>
<groupId>io.github.openfeign.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>7.0</version>
<classifier>jpa</classifier>
</path>
<path>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,11 @@
package com.lanyuanxiaoyao.leopard.core;
/**
* 静态字段
*
* @author lanyuanxiaoyao
* @version 20250829
*/
public interface Constants {
String DATABASE_PREFIX = "leopard_";
}

View File

@@ -0,0 +1,11 @@
package com.lanyuanxiaoyao.leopard.core;
import com.blinkfox.fenix.EnableFenix;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableFenix
@EntityScan(basePackageClasses = {JpaConfiguration.class})
public class JpaConfiguration {
}

View File

@@ -1,10 +1,11 @@
package com.lanyuanxiaoyao.leopard.server.entity; package com.lanyuanxiaoyao.leopard.core.entity;
import com.lanyuanxiaoyao.leopard.server.Constants; import com.lanyuanxiaoyao.leopard.core.Constants;
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity; import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
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.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import java.time.LocalDate; import java.time.LocalDate;
@@ -53,6 +54,7 @@ public class Daily extends SimpleEntity {
private Double factor; private Double factor;
@ManyToOne @ManyToOne
@JoinColumn(nullable = false)
@ToString.Exclude @ToString.Exclude
private Stock stock; private Stock stock;
} }

View File

@@ -1,7 +1,7 @@
package com.lanyuanxiaoyao.leopard.server.entity; package com.lanyuanxiaoyao.leopard.core.entity;
import com.lanyuanxiaoyao.leopard.server.Constants; import com.lanyuanxiaoyao.leopard.core.Constants;
import com.lanyuanxiaoyao.leopard.server.entity.base.SimpleEnum; import com.lanyuanxiaoyao.leopard.core.entity.base.SimpleEnum;
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity; import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
import jakarta.persistence.CascadeType; import jakarta.persistence.CascadeType;
import jakarta.persistence.Column; import jakarta.persistence.Column;
@@ -11,6 +11,7 @@ import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated; import jakarta.persistence.Enumerated;
import jakarta.persistence.OneToMany; import jakarta.persistence.OneToMany;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import java.time.LocalDate;
import java.util.Set; import java.util.Set;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
@@ -55,6 +56,8 @@ public class Stock extends SimpleEntity {
private Market market; private Market market;
@Comment("行业") @Comment("行业")
private String industry; private String industry;
@Comment("上市日期")
private LocalDate listedDate;
@OneToMany(mappedBy = "stock", cascade = CascadeType.REMOVE) @OneToMany(mappedBy = "stock", cascade = CascadeType.REMOVE)
@ToString.Exclude @ToString.Exclude

View File

@@ -1,7 +1,7 @@
package com.lanyuanxiaoyao.leopard.server.entity; package com.lanyuanxiaoyao.leopard.core.entity;
import com.lanyuanxiaoyao.leopard.server.Constants; import com.lanyuanxiaoyao.leopard.core.Constants;
import com.lanyuanxiaoyao.leopard.server.entity.base.SimpleEnum; import com.lanyuanxiaoyao.leopard.core.entity.base.SimpleEnum;
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity; import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
import jakarta.persistence.Basic; import jakarta.persistence.Basic;
import jakarta.persistence.Column; import jakarta.persistence.Column;

View File

@@ -1,6 +1,6 @@
package com.lanyuanxiaoyao.leopard.server.entity; package com.lanyuanxiaoyao.leopard.core.entity;
import com.lanyuanxiaoyao.leopard.server.Constants; import com.lanyuanxiaoyao.leopard.core.Constants;
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity; import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;

View File

@@ -1,4 +1,4 @@
package com.lanyuanxiaoyao.leopard.server.entity.base; package com.lanyuanxiaoyao.leopard.core.entity.base;
/** /**
* @author lanyuanxiaoyao * @author lanyuanxiaoyao

View File

@@ -1,6 +1,6 @@
package com.lanyuanxiaoyao.leopard.server.repository; package com.lanyuanxiaoyao.leopard.core.repository;
import com.lanyuanxiaoyao.leopard.server.entity.Daily; import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.service.template.repository.SimpleRepository; import com.lanyuanxiaoyao.service.template.repository.SimpleRepository;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
@@ -11,4 +11,7 @@ import org.springframework.stereotype.Repository;
public interface DailyRepository extends SimpleRepository<Daily> { public interface DailyRepository extends SimpleRepository<Daily> {
@Query("select distinct daily.tradeDate from Daily daily") @Query("select distinct daily.tradeDate from Daily daily")
List<LocalDate> findDistinctTradeDate(); List<LocalDate> findDistinctTradeDate();
@Query("select distinct daily.tradeDate from Daily daily where daily.stock.id = ?1")
List<LocalDate> findDistinctTradeDateByStockId(Long stockId);
} }

View File

@@ -1,6 +1,6 @@
package com.lanyuanxiaoyao.leopard.server.repository; package com.lanyuanxiaoyao.leopard.core.repository;
import com.lanyuanxiaoyao.leopard.server.entity.Stock; import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.service.template.repository.SimpleRepository; import com.lanyuanxiaoyao.service.template.repository.SimpleRepository;
import java.util.List; import java.util.List;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;

View File

@@ -0,0 +1,18 @@
package com.lanyuanxiaoyao.leopard.core.repository;
import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.service.template.repository.SimpleRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
/**
* @author lanyuanxiaoyao
* @version 20250829
*/
@Repository
public interface TaskRepository extends SimpleRepository<Task> {
@Modifying
@Query("update Task task set task.status = com.lanyuanxiaoyao.leopard.core.entity.Task.Status.FAILURE where task.status = com.lanyuanxiaoyao.leopard.core.entity.Task.Status.RUNNING")
void updateAllRunningTaskToFailure();
}

View File

@@ -1,6 +1,6 @@
package com.lanyuanxiaoyao.leopard.server.repository; package com.lanyuanxiaoyao.leopard.core.repository;
import com.lanyuanxiaoyao.leopard.server.entity.TaskTemplate; import com.lanyuanxiaoyao.leopard.core.entity.TaskTemplate;
import com.lanyuanxiaoyao.service.template.repository.SimpleRepository; import com.lanyuanxiaoyao.service.template.repository.SimpleRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;

View File

@@ -14,12 +14,9 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.lanyuanxiaoyao</groupId> <groupId>com.lanyuanxiaoyao</groupId>
<artifactId>spring-boot-service-template</artifactId> <artifactId>leopard-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
@@ -63,6 +60,11 @@
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
@@ -80,22 +82,6 @@
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
</path> </path>
<path>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>6.6.8.Final</version>
</path>
<path>
<groupId>io.github.openfeign.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>7.0</version>
<classifier>jpa</classifier>
</path>
<path>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</path>
</annotationProcessorPaths> </annotationProcessorPaths>
</configuration> </configuration>
</plugin> </plugin>

View File

@@ -1,6 +1,5 @@
package com.lanyuanxiaoyao.leopard.server; package com.lanyuanxiaoyao.leopard.server;
import com.blinkfox.fenix.EnableFenix;
import com.lanyuanxiaoyao.leopard.server.service.TuShareService; import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
import com.yomahub.liteflow.core.FlowExecutor; import com.yomahub.liteflow.core.FlowExecutor;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@@ -16,8 +15,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
* @version 20250828 * @version 20250828
*/ */
@Slf4j @Slf4j
@SpringBootApplication @SpringBootApplication(scanBasePackages = "com.lanyuanxiaoyao.leopard")
@EnableFenix
@EnableJpaAuditing @EnableJpaAuditing
public class LeopardServerApplication implements ApplicationRunner { public class LeopardServerApplication implements ApplicationRunner {
public static void main(String[] args) { public static void main(String[] args) {
@@ -31,7 +29,7 @@ public class LeopardServerApplication implements ApplicationRunner {
@Override @Override
public void run(ApplicationArguments args) { public void run(ApplicationArguments args) {
executor.execute2RespWithEL("THEN(update_daily)"); // executor.execute2RespWithEL("THEN(update_daily)");
// executor.execute2RespWithEL("THEN(update_stock)"); // executor.execute2RespWithEL("THEN(update_stock)");
} }
} }

View File

@@ -1,7 +1,7 @@
package com.lanyuanxiaoyao.leopard.server.controller; package com.lanyuanxiaoyao.leopard.server.controller;
import com.lanyuanxiaoyao.leopard.server.entity.Stock; import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.server.entity.Task; import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.leopard.server.service.StockService; import com.lanyuanxiaoyao.leopard.server.service.StockService;
import com.lanyuanxiaoyao.leopard.server.service.TaskTemplateService; import com.lanyuanxiaoyao.leopard.server.service.TaskTemplateService;
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse; import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
@@ -26,6 +26,10 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("constants") @RequestMapping("constants")
public class CommonOptionsController { public class CommonOptionsController {
public static final String COLOR_PRIMARY = "bg-primary";
public static final String COLOR_SUCCESS = "bg-success";
public static final String COLOR_WARNING = "bg-yellow-800";
public static final String COLOR_ERROR = "bg-danger";
private static final List<String> COLORS = List.of( private static final List<String> COLORS = List.of(
"bg-black", "bg-black",
"bg-primary", "bg-primary",
@@ -124,19 +128,22 @@ public class CommonOptionsController {
field field
)); ));
case "task_status" -> GlobalResponse.responseSuccess(buildMapping( case "task_status" -> GlobalResponse.responseSuccess(buildMapping(
Arrays.stream(Task.Status.values()) List.of(
.map(status -> new Mapping(status.name(), status.getChineseName())) new Mapping(Task.Status.RUNNING.name(), Task.Status.RUNNING.getChineseName(), COLOR_PRIMARY),
.toList(), new Mapping(Task.Status.SUCCESS.name(), Task.Status.SUCCESS.getChineseName(), COLOR_SUCCESS),
new Mapping(Task.Status.FAILURE.name(), Task.Status.FAILURE.getChineseName(), COLOR_ERROR),
new Mapping(Task.Status.CANCELED.name(), Task.Status.CANCELED.getChineseName(), COLOR_WARNING)
),
field field
)); ));
case "trigger_status" -> GlobalResponse.responseSuccess(buildMapping( case "trigger_status" -> GlobalResponse.responseSuccess(buildMapping(
List.of( List.of(
new Mapping(Trigger.TriggerState.NONE.name(), ""), new Mapping(Trigger.TriggerState.NONE.name(), ""),
new Mapping(Trigger.TriggerState.NORMAL.name(), "正常"), new Mapping(Trigger.TriggerState.NORMAL.name(), "正常", COLOR_PRIMARY),
new Mapping(Trigger.TriggerState.PAUSED.name(), "暂停"), new Mapping(Trigger.TriggerState.PAUSED.name(), "暂停", COLOR_WARNING),
new Mapping(Trigger.TriggerState.COMPLETE.name(), "完成"), new Mapping(Trigger.TriggerState.COMPLETE.name(), "完成", COLOR_SUCCESS),
new Mapping(Trigger.TriggerState.ERROR.name(), "错误"), new Mapping(Trigger.TriggerState.ERROR.name(), "错误", COLOR_ERROR),
new Mapping(Trigger.TriggerState.BLOCKED.name(), "阻塞") new Mapping(Trigger.TriggerState.BLOCKED.name(), "阻塞", COLOR_WARNING)
), ),
field field
)); ));
@@ -148,8 +155,7 @@ public class CommonOptionsController {
var map = mappings var map = mappings
.stream() .stream()
.collect(Collectors.toMap(Mapping::name, mapping -> { .collect(Collectors.toMap(Mapping::name, mapping -> {
var color = COLORS.get(Math.abs(mapping.name.hashCode()) % COLORS.size()); return "<span class='label %s'>%s</span>".formatted(mapping.color(), mapping.label());
return "<span class='label %s'>%s</span>".formatted(color, mapping.label());
})); }));
map.put("*", "<span class='label bg-gray-300'>%s</span>".formatted(field)); map.put("*", "<span class='label bg-gray-300'>%s</span>".formatted(field));
return map; return map;
@@ -158,6 +164,9 @@ public class CommonOptionsController {
public record Option(String label, Object value) { public record Option(String label, Object value) {
} }
public record Mapping(String name, String label) { public record Mapping(String name, String label, String color) {
public Mapping(String name, String label) {
this(name, label, COLORS.get(Math.abs(name.hashCode()) % COLORS.size()));
}
} }
} }

View File

@@ -1,9 +1,10 @@
package com.lanyuanxiaoyao.leopard.server.controller; package com.lanyuanxiaoyao.leopard.server.controller;
import com.lanyuanxiaoyao.leopard.server.entity.Stock; import com.lanyuanxiaoyao.leopard.core.entity.Stock;
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.util.function.Function; import java.util.function.Function;
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;
@@ -36,7 +37,8 @@ public class StockController extends SimpleControllerSupport<Stock, Void, StockC
stock.getName(), stock.getName(),
stock.getFullname(), stock.getFullname(),
stock.getMarket(), stock.getMarket(),
stock.getIndustry() stock.getIndustry(),
stock.getListedDate()
); );
} }
@@ -56,7 +58,8 @@ public class StockController extends SimpleControllerSupport<Stock, Void, StockC
String name, String name,
String fullname, String fullname,
Stock.Market market, Stock.Market market,
String industry String industry,
LocalDate listedDate
) { ) {
} }
} }

View File

@@ -1,9 +1,13 @@
package com.lanyuanxiaoyao.leopard.server.controller; package com.lanyuanxiaoyao.leopard.server.controller;
import com.lanyuanxiaoyao.leopard.server.entity.Task; import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.leopard.server.service.TaskService; import com.lanyuanxiaoyao.leopard.server.service.TaskService;
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.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
@@ -46,21 +50,39 @@ public class TaskController extends SimpleControllerSupport<Task, Void, TaskCont
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
private TaskCost calculateCost(LocalDateTime start, LocalDateTime finish) {
if (ObjectUtil.isNull(start) || ObjectUtil.isNull(finish)) {
return new TaskCost(null, null);
}
var duration = Duration.between(start, finish).toMillis();
return new TaskCost(
duration,
DateUtil.formatBetween(duration, BetweenFormatter.Level.SECOND)
);
}
@Override @Override
protected Function<Task, ListItem> listItemMapper() { protected Function<Task, ListItem> listItemMapper() {
return task -> new ListItem( return task -> {
var cost = calculateCost(task.getLaunchedTime(), task.getFinishedTime());
return new ListItem(
task.getId(), task.getId(),
task.getName(), task.getName(),
task.getDescription(), task.getDescription(),
task.getStatus(), task.getStatus(),
task.getLaunchedTime(), task.getLaunchedTime(),
task.getFinishedTime() task.getFinishedTime(),
cost.cost(),
cost.costText()
); );
};
} }
@Override @Override
protected Function<Task, DetailItem> detailItemMapper() { protected Function<Task, DetailItem> detailItemMapper() {
return task -> new DetailItem( return task -> {
var cost = calculateCost(task.getLaunchedTime(), task.getFinishedTime());
return new DetailItem(
task.getId(), task.getId(),
task.getName(), task.getName(),
task.getDescription(), task.getDescription(),
@@ -68,8 +90,11 @@ public class TaskController extends SimpleControllerSupport<Task, Void, TaskCont
task.getError(), task.getError(),
task.getResult(), task.getResult(),
task.getLaunchedTime(), task.getLaunchedTime(),
task.getFinishedTime() task.getFinishedTime(),
cost.cost(),
cost.costText()
); );
};
} }
public record ListItem( public record ListItem(
@@ -78,7 +103,9 @@ public class TaskController extends SimpleControllerSupport<Task, Void, TaskCont
String description, String description,
Task.Status status, Task.Status status,
LocalDateTime launchedTime, LocalDateTime launchedTime,
LocalDateTime finishedTime LocalDateTime finishedTime,
Long cost,
String costText
) { ) {
} }
@@ -90,10 +117,15 @@ public class TaskController extends SimpleControllerSupport<Task, Void, TaskCont
String error, String error,
String result, String result,
LocalDateTime launchedTime, LocalDateTime launchedTime,
LocalDateTime finishedTime LocalDateTime finishedTime,
Long cost,
String costText
) { ) {
} }
public record ExecuteRequest(Long templateId, Map<String, Object> params) { public record ExecuteRequest(Long templateId, Map<String, Object> params) {
} }
public record TaskCost(Long cost, String costText) {
}
} }

View File

@@ -1,6 +1,6 @@
package com.lanyuanxiaoyao.leopard.server.controller; package com.lanyuanxiaoyao.leopard.server.controller;
import com.lanyuanxiaoyao.leopard.server.entity.TaskTemplate; import com.lanyuanxiaoyao.leopard.core.entity.TaskTemplate;
import com.lanyuanxiaoyao.leopard.server.service.TaskTemplateService; import com.lanyuanxiaoyao.leopard.server.service.TaskTemplateService;
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport; import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
import java.util.function.Function; import java.util.function.Function;

View File

@@ -1,13 +0,0 @@
package com.lanyuanxiaoyao.leopard.server.repository;
import com.lanyuanxiaoyao.leopard.server.entity.Task;
import com.lanyuanxiaoyao.service.template.repository.SimpleRepository;
import org.springframework.stereotype.Repository;
/**
* @author lanyuanxiaoyao
* @version 20250829
*/
@Repository
public interface TaskRepository extends SimpleRepository<Task> {
}

View File

@@ -1,7 +1,7 @@
package com.lanyuanxiaoyao.leopard.server.service; package com.lanyuanxiaoyao.leopard.server.service;
import com.lanyuanxiaoyao.leopard.server.entity.Daily; import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.server.repository.DailyRepository; import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository;
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport; import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
@@ -19,4 +19,8 @@ public class DailyService extends SimpleServiceSupport<Daily> {
public List<LocalDate> findDistinctTradeDate() { public List<LocalDate> findDistinctTradeDate() {
return dailyRepository.findDistinctTradeDate(); return dailyRepository.findDistinctTradeDate();
} }
public List<LocalDate> findDistinctTradeDateByStockId(Long stockId) {
return dailyRepository.findDistinctTradeDateByStockId(stockId);
}
} }

View File

@@ -2,6 +2,7 @@ package com.lanyuanxiaoyao.leopard.server.service;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.lanyuanxiaoyao.leopard.server.service.task.TaskMonitorNodes;
import com.yomahub.liteflow.core.FlowExecutor; import com.yomahub.liteflow.core.FlowExecutor;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
@@ -95,7 +96,8 @@ public class QuartzService {
if (ObjectUtil.isNotNull(templateId)) { if (ObjectUtil.isNotNull(templateId)) {
var template = taskTemplateService.detail(templateId); var template = taskTemplateService.detail(templateId);
var params = (Map<String, Object>) dataMap.getOrDefault("params", Map.of()); var params = (Map<String, Object>) dataMap.getOrDefault("params", Map.of());
flowExecutor.execute2Resp(template.getChain(), params, context); var monitorContext = new TaskMonitorNodes.TaskMonitorContext(template);
flowExecutor.execute2Resp(template.getChain(), params, monitorContext);
} }
} }
} }

View File

@@ -1,7 +1,7 @@
package com.lanyuanxiaoyao.leopard.server.service; package com.lanyuanxiaoyao.leopard.server.service;
import com.lanyuanxiaoyao.leopard.server.entity.Stock; import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.server.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.util.List; import java.util.List;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;

View File

@@ -1,12 +1,15 @@
package com.lanyuanxiaoyao.leopard.server.service; package com.lanyuanxiaoyao.leopard.server.service;
import com.lanyuanxiaoyao.leopard.server.entity.Task; import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.leopard.server.repository.TaskRepository; import com.lanyuanxiaoyao.leopard.core.repository.TaskRepository;
import com.lanyuanxiaoyao.leopard.server.service.task.TaskMonitorNodes; import com.lanyuanxiaoyao.leopard.server.service.task.TaskMonitorNodes;
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport; import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
import com.yomahub.liteflow.core.FlowExecutor; import com.yomahub.liteflow.core.FlowExecutor;
import jakarta.transaction.Transactional;
import java.util.Map; import java.util.Map;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
@@ -16,15 +19,24 @@ import org.springframework.stereotype.Service;
@Slf4j @Slf4j
@Service @Service
public class TaskService extends SimpleServiceSupport<Task> { public class TaskService extends SimpleServiceSupport<Task> {
private final TaskRepository taskRepository;
private final TaskTemplateService taskTemplateService; private final TaskTemplateService taskTemplateService;
private final FlowExecutor flowExecutor; private final FlowExecutor flowExecutor;
public TaskService(TaskRepository repository, TaskTemplateService taskTemplateService, @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") FlowExecutor flowExecutor) { public TaskService(TaskRepository repository, TaskTemplateService taskTemplateService, @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") FlowExecutor flowExecutor) {
super(repository); super(repository);
this.taskRepository = repository;
this.taskTemplateService = taskTemplateService; this.taskTemplateService = taskTemplateService;
this.flowExecutor = flowExecutor; this.flowExecutor = flowExecutor;
} }
@Transactional(rollbackOn = Throwable.class)
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady() {
log.warn("更新所有未完成的任务状态为失败");
taskRepository.updateAllRunningTaskToFailure();
}
public void execute(Long templateId, Map<String, Object> params) { public void execute(Long templateId, Map<String, Object> params) {
var template = taskTemplateService.detail(templateId); var template = taskTemplateService.detail(templateId);
var context = new TaskMonitorNodes.TaskMonitorContext(template); var context = new TaskMonitorNodes.TaskMonitorContext(template);

View File

@@ -1,7 +1,7 @@
package com.lanyuanxiaoyao.leopard.server.service; package com.lanyuanxiaoyao.leopard.server.service;
import com.lanyuanxiaoyao.leopard.server.entity.TaskTemplate; import com.lanyuanxiaoyao.leopard.core.entity.TaskTemplate;
import com.lanyuanxiaoyao.leopard.server.repository.TaskTemplateRepository; import com.lanyuanxiaoyao.leopard.core.repository.TaskTemplateRepository;
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport; import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;

View File

@@ -45,8 +45,8 @@ public class TuShareService {
public TuShareResponse stockList() { public TuShareResponse stockList() {
var response = HttpUtil.post(API_URL, buildRequest( var response = HttpUtil.post(API_URL, buildRequest(
"stock_basic", "stock_basic",
Map.of("list_status", "L"), Map.of("list_status", "L", "market", "主板", "exchange", "SSE,SZSE"),
List.of("ts_code", "name", "fullname", "exchange", "industry") List.of("ts_code", "name", "fullname", "exchange", "industry", "list_date")
)); ));
var tuShareResponse = mapper.readValue(response, TuShareResponse.class); var tuShareResponse = mapper.readValue(response, TuShareResponse.class);
if (tuShareResponse.code != 0) { if (tuShareResponse.code != 0) {

View File

@@ -0,0 +1,77 @@
package com.lanyuanxiaoyao.leopard.server.service.task;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.server.service.DailyService;
import com.lanyuanxiaoyao.leopard.server.service.StockService;
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@LiteflowComponent("check_daily")
public class CheckDailyNode extends NodeComponent {
private final StockService stockService;
private final DailyService dailyService;
private final TuShareService tuShareService;
public CheckDailyNode(StockService stockService, DailyService dailyService, TuShareService tuShareService) {
this.stockService = stockService;
this.dailyService = dailyService;
this.tuShareService = tuShareService;
}
@Override
public void process() {
var reports = new ArrayList<MissedTradeReport>();
var stocks = stockService.list();
var exchanges = stocks.stream().map(Stock::getMarket).distinct().toList();
for (Stock.Market exchange : exchanges) {
var nowDate = LocalDate.now();
var allTradeDates = tuShareService.tradeDateList(exchange.name())
.data()
.items()
.stream()
.map(item -> LocalDate.parse(item.get(0), TuShareService.TRADE_FORMAT))
.filter(date -> date.isBefore(nowDate) || date.isEqual(nowDate))
.toList();
for (Stock stock : stocks) {
if (exchange.equals(stock.getMarket())) {
var existsTradeDates = dailyService.findDistinctTradeDateByStockId(stock.getId());
var missedTradeDates = allTradeDates.stream()
.filter(date -> date.isBefore(stock.getListedDate()))
.filter(date -> !existsTradeDates.contains(date))
.toList();
if (ObjectUtil.isNotEmpty(missedTradeDates)) {
reports.add(new MissedTradeReport(
stock.getCode(),
stock.getName(),
missedTradeDates
));
}
}
}
}
if (ObjectUtil.isNotEmpty(reports)) {
var context = getContextBean(TaskMonitorNodes.TaskMonitorContext.class);
context.setTaskResult(
reports.stream()
.map(report -> StrUtil.format("{}{})缺少如下交易日数据:{}", report.name(), report.code(), report.missedTradeDates().stream().map(LocalDate::toString).collect(Collectors.joining(", "))))
.collect(Collectors.joining("\n"))
);
}
}
public record MissedTradeReport(
String code,
String name,
List<LocalDate> missedTradeDates
) {
}
}

View File

@@ -2,8 +2,8 @@ package com.lanyuanxiaoyao.leopard.server.service.task;
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.server.entity.Task; import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.leopard.server.entity.TaskTemplate; import com.lanyuanxiaoyao.leopard.core.entity.TaskTemplate;
import com.lanyuanxiaoyao.leopard.server.service.TaskService; import com.lanyuanxiaoyao.leopard.server.service.TaskService;
import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowFact; import com.yomahub.liteflow.annotation.LiteflowFact;

View File

@@ -1,10 +1,9 @@
package com.lanyuanxiaoyao.leopard.server.service.task; package com.lanyuanxiaoyao.leopard.server.service.task;
import cn.hutool.core.thread.ThreadUtil;
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.server.entity.Daily; import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.server.entity.Stock; import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.server.service.DailyService; import com.lanyuanxiaoyao.leopard.server.service.DailyService;
import com.lanyuanxiaoyao.leopard.server.service.StockService; import com.lanyuanxiaoyao.leopard.server.service.StockService;
import com.lanyuanxiaoyao.leopard.server.service.TuShareService; import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
@@ -52,50 +51,49 @@ public class UpdateDailyNode extends NodeComponent {
.filter(date -> !existsTradeDates.contains(date)) .filter(date -> !existsTradeDates.contains(date))
.sorted() .sorted()
.toList(); .toList();
log.info("Target: {}", targetDates);
var stocks = stockService.list(); var stocks = stockService.list();
var stocksMap = stocks.stream().collect(Collectors.toMap(Stock::getCode, stock -> stock)); var stocksMap = stocks.stream().collect(Collectors.toMap(Stock::getCode, stock -> stock));
for (LocalDate tradeDate : targetDates) { for (LocalDate tradeDate : targetDates) {
log.info("Trade date: {}", tradeDate);
var factorResponse = tuShareService.factorList(tradeDate); var factorResponse = tuShareService.factorList(tradeDate);
var factorMap = new HashMap<String, Double>(); var factorMap = new HashMap<String, Double>();
for (List<String> item : factorResponse.data().items()) { for (List<String> item : factorResponse.data().items()) {
factorMap.put(item.get(0), Double.valueOf(item.get(2))); factorMap.put(item.get(0), Double.valueOf(item.get(2)));
} }
log.info("Factor: {}", factorMap);
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(LocalDate.parse(item.get(1), TuShareService.TRADE_FORMAT));
daily.setOpen(Double.valueOf(item.get(2))); daily.setOpen(item.get(2) == null ? null : Double.valueOf(item.get(2)));
daily.setHigh(Double.valueOf(item.get(3))); daily.setHigh(item.get(3) == null ? null : Double.valueOf(item.get(3)));
daily.setLow(Double.valueOf(item.get(4))); daily.setLow(item.get(4) == null ? null : Double.valueOf(item.get(4)));
daily.setClose(Double.valueOf(item.get(5))); daily.setClose(item.get(5) == null ? null : Double.valueOf(item.get(5)));
daily.setPreviousClose(Double.valueOf(item.get(6))); daily.setPreviousClose(item.get(6) == null ? null : Double.valueOf(item.get(6)));
daily.setPriceChangeAmount(Double.valueOf(item.get(7))); daily.setPriceChangeAmount(item.get(7) == null ? null : Double.valueOf(item.get(7)));
daily.setPriceFluctuationRange(Double.valueOf(item.get(8))); daily.setPriceFluctuationRange(item.get(8) == null ? null : Double.valueOf(item.get(8)));
daily.setVolume(Double.valueOf(item.get(9))); daily.setVolume(item.get(9) == null ? null : Double.valueOf(item.get(9)));
daily.setTurnover(Double.valueOf(item.get(10))); daily.setTurnover(item.get(10) == null ? null : Double.valueOf(item.get(10)));
daily.setFactor(factor); daily.setFactor(factor);
daily.setStock(stock); daily.setStock(stock);
log.info("Daily: {}", daily);
dailyService.save(daily); dailyService.save(daily);
} }
} }
log.info("Trade date: {} {}", tradeDate, count);
return true; return true;
} catch (Exception exception) { } catch (Exception exception) {
log.error("Error", exception);
status.setRollbackOnly(); status.setRollbackOnly();
return false; return false;
} }
}); });
ThreadUtil.safeSleep(1000);
} }
} }
} }

View File

@@ -1,12 +1,13 @@
package com.lanyuanxiaoyao.leopard.server.service.task; package com.lanyuanxiaoyao.leopard.server.service.task;
import cn.hutool.core.util.EnumUtil; import cn.hutool.core.util.EnumUtil;
import com.lanyuanxiaoyao.leopard.server.entity.Stock; import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.server.service.StockService; import com.lanyuanxiaoyao.leopard.server.service.StockService;
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 com.yomahub.liteflow.core.NodeComponent;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import java.time.LocalDate;
import java.util.HashSet; import java.util.HashSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -35,12 +36,14 @@ public class UpdateStockNode extends NodeComponent {
var fullname = item.get(2); var fullname = item.get(2);
var market = EnumUtil.fromString(Stock.Market.class, item.get(3)); var market = EnumUtil.fromString(Stock.Market.class, item.get(3));
var industry = item.get(4); var industry = item.get(4);
var listedDate = LocalDate.parse(item.get(5), TuShareService.TRADE_FORMAT);
if (stocksMap.containsKey(code)) { if (stocksMap.containsKey(code)) {
var stock = stocksMap.get(code); var stock = stocksMap.get(code);
stock.setName(name); stock.setName(name);
stock.setFullname(fullname); stock.setFullname(fullname);
stock.setMarket(market); stock.setMarket(market);
stock.setIndustry(industry); stock.setIndustry(industry);
stock.setListedDate(listedDate);
} else { } else {
var stock = new Stock(); var stock = new Stock();
stock.setCode(code); stock.setCode(code);
@@ -48,6 +51,7 @@ public class UpdateStockNode extends NodeComponent {
stock.setFullname(fullname); stock.setFullname(fullname);
stock.setMarket(market); stock.setMarket(market);
stock.setIndustry(industry); stock.setIndustry(industry);
stock.setListedDate(listedDate);
stocks.add(stock); stocks.add(stock);
} }
targetCodes.add(code); targetCodes.add(code);

View File

@@ -9,18 +9,31 @@ spring:
async: async:
request-timeout: 3600000 request-timeout: 3600000
datasource: datasource:
url: jdbc:mysql://mysql.lanyuanxiaoyao.com:43780/leopard?useSSL=false # url: jdbc:mysql://mysql.lanyuanxiaoyao.com:43780/leopard?useSSL=false
# url: jdbc:mysql://192.168.31.127:3780/leopard?useSSL=false
url: jdbc:postgresql://192.168.31.127:6785/leopard
username: leopard username: leopard
password: '9NEzFzovnddf@PyEP?e*AYAWnCyd7UhYwQK$pJf>7?ccFiN^x4$eKEZ5~E<7<+~X' password: '9NEzFzovnddf@PyEP?e*AYAWnCyd7UhYwQK$pJf>7?ccFiN^x4$eKEZ5~E<7<+~X'
driver-class-name: com.mysql.cj.jdbc.Driver # driver-class-name: com.mysql.cj.jdbc.Driver
driver-class-name: org.postgresql.Driver
jpa: jpa:
generate-ddl: true generate-ddl: true
properties:
hibernate:
dialect: org.hibernate.dialect.PostgresPlusDialect
quartz: quartz:
wait-for-jobs-to-complete-on-shutdown: true wait-for-jobs-to-complete-on-shutdown: true
startup-delay: 30s startup-delay: 30s
job-store-type: jdbc job-store-type: jdbc
jdbc: jdbc:
platform: mysql # platform: mysql
platform: postgres
# initialize-schema: always
properties:
org:
quartz:
jobStore:
driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
fenix: fenix:
print-banner: false print-banner: false
liteflow: liteflow:

View File

@@ -7,4 +7,7 @@
<chain id="update_daily_information"> <chain id="update_daily_information">
CATCH(THEN(task_start, update_daily, task_end)).DO(task_error) CATCH(THEN(task_start, update_daily, task_end)).DO(task_error)
</chain> </chain>
<chain id="check_daily">
CATCH(THEN(task_start, check_daily, task_end)).DO(task_error)
</chain>
</flow> </flow>

View File

@@ -9,14 +9,18 @@ Content-Type: application/json
"api_name": "stock_basic", "api_name": "stock_basic",
"token": "{{api_key}}", "token": "{{api_key}}",
"params": { "params": {
"list_status": "D,P,L" "list_status": "L",
"market": "主板",
"exchange": "SSE,SZSE"
}, },
"fields": [ "fields": [
"ts_code", "ts_code",
"name", "name",
"fullname", "fullname",
"exchange", "exchange",
"industry" "industry",
"market",
"list_date"
] ]
} }
@@ -54,7 +58,7 @@ Content-Type: application/json
"api_name": "daily", "api_name": "daily",
"token": "{{api_key}}", "token": "{{api_key}}",
"params": { "params": {
"trade_date": "19901219" "trade_date": "19931213"
}, },
"fields": [ "fields": [
"ts_code", "ts_code",

View File

@@ -3,6 +3,7 @@ import {
amisRender, amisRender,
commonInfo, commonInfo,
crudCommonOptions, crudCommonOptions,
date,
paginationTemplate, paginationTemplate,
remoteMappings, remoteMappings,
remoteOptions, remoteOptions,
@@ -123,6 +124,12 @@ function StockList() {
label: '行业', label: '行业',
width: 150, width: 150,
}, },
{
label: '上市日期',
width: 100,
align: 'center',
...date('listedDate'),
},
{ {
type: 'operation', type: 'operation',
label: '操作', label: '操作',

View File

@@ -41,6 +41,13 @@ function TaskList() {
width: 100, width: 100,
...remoteMappings('task_status', 'status'), ...remoteMappings('task_status', 'status'),
}, },
{
label: '耗时',
type: 'tpl',
align: 'center',
width: 150,
tpl: "${IF(costText, costText, '/')}",
},
{ {
name: 'launchedTime', name: 'launchedTime',
label: '启动时间', label: '启动时间',

View File

@@ -254,6 +254,13 @@ export function time(field: string) {
} }
} }
export function date(field: string) {
return {
type: 'tpl',
tpl: `\${IF(${field}, DATETOSTR(${field}, 'YYYY-MM-DD'), '/')}`,
}
}
export function pictureFromIds(field: string) { export function pictureFromIds(field: string) {
return `\${ARRAYMAP(${field},id => '${commonInfo.baseUrl}/upload/download/' + id)}` return `\${ARRAYMAP(${field},id => '${commonInfo.baseUrl}/upload/download/' + id)}`
} }

20
pom.xml
View File

@@ -10,6 +10,7 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>leopard-core</module>
<module>leopard-server</module> <module>leopard-server</module>
</modules> </modules>
@@ -38,6 +39,12 @@
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency>
<groupId>com.lanyuanxiaoyao</groupId>
<artifactId>leopard-core</artifactId>
<version>1.0.0</version>
</dependency>
<dependency> <dependency>
<groupId>com.lanyuanxiaoyao</groupId> <groupId>com.lanyuanxiaoyao</groupId>
<artifactId>spring-boot-service-template</artifactId> <artifactId>spring-boot-service-template</artifactId>
@@ -95,4 +102,17 @@
</pluginManagement> </pluginManagement>
</build> </build>
<distributionManagement>
<repository>
<id>${releases.id}</id>
<name>${releases.name}</name>
<url>${releases.url}</url>
</repository>
<snapshotRepository>
<id>${snapshots.id}</id>
<name>${snapshots.name}</name>
<url>${snapshots.url}</url>
</snapshotRepository>
</distributionManagement>
</project> </project>