Bläddra i källkod

update:coin重构v1

tujidelv 2 år sedan
förälder
incheckning
1e43c1ae75

+ 12 - 0
pom.xml

@@ -131,6 +131,18 @@
             <version>4.5.8</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <version>2.7.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-cp</artifactId>
+            <version>4.4.0</version>
+        </dependency>
+
+
         <!-- https://mvnrepository.com/artifact/ch.ethz.ganymed/ganymed-ssh2 -->
         <dependency>
             <groupId>ch.ethz.ganymed</groupId>

+ 41 - 0
src/main/java/top/lvzhiqiang/config/ExecutorConfig.java

@@ -0,0 +1,41 @@
+package top.lvzhiqiang.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+/**
+ * 线程池配置类
+ *
+ * @author shiyong
+ * 2019-11-18 15:44
+ */
+@Configuration
+@EnableAsync
+public class ExecutorConfig {
+
+    /**
+     * 线程池
+     *
+     * @return org.springframework.core.task.TaskExecutor
+     * @author shiyong
+     * 2019/11/18 15:59
+     */
+    @Bean("coinTaskExecutor")
+    public TaskExecutor coinTaskExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        // 配置核心线程数
+        executor.setCorePoolSize(10);
+        // 配置最大线程数
+        executor.setMaxPoolSize(100);
+        // 配置队列容量
+        executor.setQueueCapacity(99999);
+        // 配置线程池中的线程的名称前缀
+        executor.setThreadNamePrefix("coin-exec-");
+        // 执行初始化
+        executor.initialize();
+        return executor;
+    }
+}

+ 5 - 1
src/main/java/top/lvzhiqiang/config/InitRunner.java

@@ -6,6 +6,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 import top.lvzhiqiang.entity.DicCode;
 import top.lvzhiqiang.mapper.DicCodeMapper;
+import top.lvzhiqiang.service.CoinService;
 
 import javax.annotation.Resource;
 import java.util.ArrayList;
@@ -26,8 +27,11 @@ public class InitRunner implements ApplicationRunner {
     @Resource
     private DicCodeMapper dicCodeMapper;
 
+    @Resource
+    private CoinService coinService;
+
     @Override
     public void run(ApplicationArguments args) {
-
+        coinService.monitorJob();
     }
 }

+ 37 - 0
src/main/java/top/lvzhiqiang/config/MyCoinJobs.java

@@ -0,0 +1,37 @@
+package top.lvzhiqiang.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import top.lvzhiqiang.service.CoinService;
+import top.lvzhiqiang.util.DateUtils;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+
+/**
+ * Coin定时任务
+ *
+ * @author lvzhiqiang
+ * 2023/9/10 13:58
+ */
+@Component
+@Slf4j
+public class MyCoinJobs {
+
+    @Resource
+    private CoinService coinService;
+
+    private static final String SCHEDULED_ZONE = "Asia/Shanghai";
+
+    /**
+     * 每小时执行一次
+     */
+    @Scheduled(cron = "0 * * * *", zone = SCHEDULED_ZONE)
+    public void syncData() {
+        String startTime = String.valueOf(DateUtils.localDateTimeToMilliseconds(LocalDateTime.now().minusDays(1)));
+        String endTime = String.valueOf(System.currentTimeMillis());
+        String pageSize = "100";
+        coinService.syncData(startTime, endTime, pageSize);
+    }
+}

+ 38 - 0
src/main/java/top/lvzhiqiang/config/WorkWeixinAutoConfiguration.java

@@ -0,0 +1,38 @@
+package top.lvzhiqiang.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 企业微信自动配置
+ * <p>当且仅当{@code work.weixin.enabled}配置为false时禁用</p>
+ *
+ * @author ziyan.li
+ * @since 16:03 2023/1/3
+ */
+@Configuration
+@EnableConfigurationProperties(WorkWeixinProperties.class)
+@ConditionalOnProperty(value = "work.weixin.enabled", havingValue = "true", matchIfMissing = true)
+public class WorkWeixinAutoConfiguration {
+
+    /**
+     * 保持在内存中的WxCpService
+     *
+     * @param properties 配置项
+     * @return service
+     */
+    @Bean
+    @ConditionalOnMissingBean
+    public WxCpService wxCpServiceInMemory(WorkWeixinProperties properties) {
+        WxCpDefaultConfigImpl wxCpDefaultConfig = new WxCpDefaultConfigImpl();
+        wxCpDefaultConfig.setCorpId(properties.getCorpId());
+        wxCpDefaultConfig.setAgentId(properties.getAgentId());
+        wxCpDefaultConfig.setCorpSecret(properties.getSecret());
+        WxCpServiceImpl wxCpService = new WxCpServiceImpl();
+        wxCpService.setWxCpConfigStorage(wxCpDefaultConfig);
+        return wxCpService;
+    }
+}

+ 38 - 0
src/main/java/top/lvzhiqiang/config/WorkWeixinProperties.java

@@ -0,0 +1,38 @@
+package top.lvzhiqiang.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * 企业微信相关配置项
+ *
+ * @author ziyan.li
+ * @since 15:56 2023/1/3
+ */
+@ConfigurationProperties(prefix = WorkWeixinProperties.PROPERTY_PREFIX)
+@Data
+public class WorkWeixinProperties {
+
+    /* 配置项前缀 */
+    public static final String PROPERTY_PREFIX = "work.weixin";
+
+    /**
+     * 是否启用企业微信告警
+     */
+    private boolean enabled;
+
+    /**
+     * 企业ID
+     */
+    private String corpId;
+
+    /**
+     * 应用ID
+     */
+    private Integer agentId;
+
+    /**
+     * 应用密钥
+     */
+    private String secret;
+}

+ 0 - 35
src/main/java/top/lvzhiqiang/controller/CoinBgController.java

@@ -1,35 +0,0 @@
-package top.lvzhiqiang.controller;
-
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-import top.lvzhiqiang.service.CoinService;
-
-import javax.annotation.Resource;
-
-/**
- * CoinBg Controller
- *
- * @author lvzhiqiang
- * 2023/9/5 15:23
- */
-@Controller
-@RequestMapping("/bg/coin")
-public class CoinBgController {
-
-    @Resource
-    private CoinService coinService;
-
-    /**
-     * 获取全部合约仓位信息V2
-     *
-     * @author lvzhiqiang
-     * 2023/9/5 15:23
-     */
-    @RequestMapping("/findAllPositionv2")
-    @ResponseBody
-    public String findAllPositionv2() {
-
-        return coinService.findAllPositionv2();
-    }
-}

+ 27 - 15
src/main/java/top/lvzhiqiang/controller/CoinController.java

@@ -3,14 +3,16 @@ package top.lvzhiqiang.controller;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
+import top.lvzhiqiang.entity.CoinApiConfig;
+import top.lvzhiqiang.exception.ParameterException;
+import top.lvzhiqiang.service.CoinApiConfigService;
 import top.lvzhiqiang.service.CoinService;
-import top.lvzhiqiang.util.DateUtils;
 
 import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
+import java.util.List;
 
 /**
  * Coin Controller
@@ -24,24 +26,34 @@ public class CoinController {
 
     @Resource
     private CoinService coinService;
+    @Resource
+    private CoinApiConfigService coinApiConfigService;
+
+    /**
+     * 获取API配置信息
+     *
+     * @author lvzhiqiang
+     * 2023/9/5 15:23
+     */
+    @PostMapping("/findApiConfig")
+    public List<CoinApiConfig> findApiConfig() {
+        List<CoinApiConfig> all = coinApiConfigService.findByParams(null, null, null, null, 1);
+
+        return all;
+    }
 
     /**
-     * 获取全部合约仓位信息V2
+     * 主查询
      *
      * @author lvzhiqiang
      * 2023/9/5 15:23
      */
-    @PostMapping("/findAllPositionv2")
-    public JSONArray findAllPositionv2() {
-        JSONArray jsonArray = coinService.handleAllPositionV2().getJSONArray("data");
-        for (int i = 0; i < jsonArray.size(); i++) {
-            JSONObject jsonObject = jsonArray.getJSONObject(i);
-            jsonObject.put("cTime", DateUtils.timeToString(jsonObject.getLong("cTime")));
-            jsonObject.put("margin", new BigDecimal(jsonObject.getString("margin")).setScale(4, RoundingMode.HALF_UP));
-            jsonObject.put("averageOpenPrice", new BigDecimal(jsonObject.getString("averageOpenPrice")).setScale(4, RoundingMode.HALF_UP));
-            jsonObject.put("unrealizedPL", new BigDecimal(jsonObject.getString("unrealizedPL")).setScale(4, RoundingMode.HALF_UP));
-            jsonObject.put("liquidationPrice", new BigDecimal(jsonObject.getString("liquidationPrice")).setScale(4, RoundingMode.HALF_UP));
+    @PostMapping("/mainSearch")
+    public JSONArray mainSearch(@RequestBody JSONObject params) {
+        if (!params.containsKey("nameEn")) {
+            throw new ParameterException("参数错误!");
         }
-        return jsonArray;
+
+        return coinService.mainSearch(params);
     }
 }

+ 79 - 0
src/main/java/top/lvzhiqiang/entity/CoinApiConfig.java

@@ -0,0 +1,79 @@
+package top.lvzhiqiang.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * coin-API-配置表
+ *
+ * @author lvzhiqiang
+ * 2023/9/9 0:37
+ */
+@Data
+public class CoinApiConfig implements Serializable {
+
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * API名称cn
+     */
+    private String nameCn;
+
+    /**
+     * API名称en
+     */
+    private String nameEn;
+
+    /**
+     * API地址
+     */
+    private String url;
+
+    /**
+     * 返回值en,逗号隔开
+     */
+    private String returnEn;
+
+    /**
+     * 返回值cn,逗号隔开
+     */
+    private String returnCn;
+
+    /**
+     * 类型1{1:现货,2:合约}
+     */
+    private Integer type;
+
+    /**
+     * 类型2{1:实时,2:非实时}
+     */
+    private Integer type2;
+
+    /**
+     * 状态{1:正常,2:已禁用}
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    /**
+     * 最后修改时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime modifyTime;
+
+    /**
+     * 删除标志{1:正常,2:已删除}
+     */
+    private Integer deleteFlag;
+}

+ 117 - 0
src/main/java/top/lvzhiqiang/entity/CoinHistoryOrder.java

@@ -0,0 +1,117 @@
+package top.lvzhiqiang.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * coin-历史委托表
+ *
+ * @author lvzhiqiang
+ * 2023/9/9 0:37
+ */
+@Data
+public class CoinHistoryOrder implements Serializable {
+
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     *
+     */
+    private String symbol;
+    /**
+     *
+     */
+    private String size;
+    /**
+     *
+     */
+    private String orderId;
+    /**
+     *
+     */
+    private String clientOid;
+    /**
+     *
+     */
+    private String filledQty;
+    /**
+     *
+     */
+    private String fee;
+    /**
+     *
+     */
+    private String price;
+    /**
+     *
+     */
+    private String priceAvg;
+    /**
+     *
+     */
+    private String state;
+    /**
+     *
+     */
+    private String side;
+    /**
+     *
+     */
+    private String timeInForce;
+    /**
+     *
+     */
+    private String totalProfits;
+    /**
+     *
+     */
+    private String posSide;
+    /**
+     *
+     */
+    private String marginCoin;
+    /**
+     *
+     */
+    private String leverage;
+    /**
+     *
+     */
+    private String marginMode;
+    /**
+     *
+     */
+    private String orderType;
+    /**
+     *
+     */
+    private String reduceOnly;
+    /**
+     *
+     */
+    private String enterPointSource;
+    /**
+     *
+     */
+    private String tradeSide;
+    /**
+     *
+     */
+    private String holdMode;
+    /**
+     *
+     */
+    private String orderSource;
+    /**
+     *
+     */
+    private String cTime;
+    /**
+     *
+     */
+    private String uTime;
+}

+ 66 - 0
src/main/java/top/lvzhiqiang/mapper/CoinApiConfigMapper.java

@@ -0,0 +1,66 @@
+package top.lvzhiqiang.mapper;
+
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Select;
+import top.lvzhiqiang.entity.CoinApiConfig;
+
+import java.util.List;
+
+/**
+ * coin-API-配置Mapper
+ *
+ * @author lvzhiqiang
+ * 2023/9/9 17:37
+ */
+public interface CoinApiConfigMapper {
+
+    /**
+     * 删除所有
+     */
+    @Delete("DELETE FROM coin_api_config")
+    void deleteAll();
+
+    /**
+     * 批量新增
+     *
+     * @param coinApiConfigList
+     */
+    @Insert({"<script>" +
+            "INSERT INTO coin_api_config(name_cn, name_en, url, return_en, return_cn, type, type2, status, create_time, modify_time) " +
+            "VALUES " +
+            "<foreach collection='list' item='bac' index=\"index\" separator=\",\">" +
+            "   (#{bac.nameCn}, #{bac.nameEn}, #{bac.url}, #{bac.returnEn}, #{bac.returnCn}, #{bac.type}, #{bac.type2}, #{bac.status}, now(), now())" +
+            " </foreach>" +
+            "</script>"})
+    void insertList(List<CoinApiConfig> coinApiConfigList);
+
+    /**
+     * 查询所有
+     */
+    @Select("SELECT * FROM coin_api_config WHERE delete_flag = 1")
+    List<CoinApiConfig> findAll();
+
+    /**
+     * 根据codeDesc模糊查询
+     */
+    @Select({"<script>" +
+            "select *  from coin_api_config WHERE delete_flag = 1" +
+            "<if test=\"nameCn != null and nameCn != ''\">" +
+            "   and name_cn like concat('%',#{nameCn},'%')" +
+            "</if>" +
+            "<if test=\"url != null and url != ''\">" +
+            "   and url like concat('%',#{url},'%')" +
+            "</if>" +
+            "<if test=\"type != null \">" +
+            "   and type = #{type}" +
+            "</if>" +
+            "<if test=\"type2 != null \">" +
+            "   and type2 = #{type2}" +
+            "</if>" +
+            "<if test=\"status != null \">" +
+            "   and status = #{status}" +
+            "</if>" +
+            "</script>"})
+    List<CoinApiConfig> findByParams(String nameCn, String url, Integer type, Integer type2, Integer status);
+}

+ 28 - 0
src/main/java/top/lvzhiqiang/mapper/CoinMapper.java

@@ -0,0 +1,28 @@
+package top.lvzhiqiang.mapper;
+
+import org.apache.ibatis.annotations.Insert;
+import top.lvzhiqiang.entity.CoinHistoryOrder;
+
+import java.util.List;
+
+/**
+ * coin-Mapper
+ *
+ * @author lvzhiqiang
+ * 2023/9/9 17:37
+ */
+public interface CoinMapper {
+
+    @Insert({"<script>" +
+            "INSERT ignore INTO coin_order_history(symbol,size,orderId,clientOid,filledQty,fee,price,priceAvg,state,side" +
+            ",timeInForce,totalProfits,posSide,marginCoin,leverage,marginMode,orderType,reduceOnly,enterPointSource,tradeSide" +
+            ",holdMode,orderSource,cTime,uTime)" +
+            " VALUES " +
+            "<foreach collection='list' item='p' index=\"index\" separator=\",\">" +
+            "   ( #{p.symbol}, #{p.size}, #{p.orderId}, #{p.clientOid}, #{p.filledQty}, #{p.fee}, #{p.price}, #{p.priceAvg}, #{p.state}" +
+            ", #{p.side}, #{p.timeInForce}, #{p.totalProfits}, #{p.posSide}, #{p.marginCoin}, #{p.leverage}, #{p.marginMode}, #{p.orderType}" +
+            ", #{p.reduceOnly}, #{p.enterPointSource}, #{p.tradeSide}, #{p.holdMode}, #{p.orderSource}, #{p.cTime}, #{p.uTime})" +
+            "</foreach>" +
+            "</script>"})
+    int insertHistoryOrderList(List<CoinHistoryOrder> historyOrderList);
+}

+ 40 - 0
src/main/java/top/lvzhiqiang/service/CoinApiConfigService.java

@@ -0,0 +1,40 @@
+package top.lvzhiqiang.service;
+
+import top.lvzhiqiang.entity.CoinApiConfig;
+
+import java.util.List;
+
+/**
+ * coin-API-配置Service
+ *
+ * @author lvzhiqiang
+ * 2023/9/9 17:37
+ */
+public interface CoinApiConfigService {
+
+    /**
+     * 删除所有
+     */
+    void deleteAll();
+
+    /**
+     * 批量新增
+     *
+     * @return
+     */
+    void insertList(List<CoinApiConfig> coinApiConfigList);
+
+    /**
+     * 查询所有
+     *
+     * @return
+     */
+    List<CoinApiConfig> findAll();
+
+    /**
+     * 多参数查询
+     *
+     * @return
+     */
+    List<CoinApiConfig> findByParams(String nameCn, String url, Integer type, Integer type2, Integer status);
+}

+ 9 - 5
src/main/java/top/lvzhiqiang/service/CoinService.java

@@ -1,5 +1,6 @@
 package top.lvzhiqiang.service;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 
 /**
@@ -12,13 +13,16 @@ public interface CoinService {
 
     String monitorJob();
 
+    void monitorAlarm(JSONObject order);
+
+
     /**
-     * 获取全部合约仓位信息V2
+     * 主查询
      *
-     * @author lvzhiqiang
-     * 2023/9/5 15:23
+     * @param params
+     * @return
      */
-    String findAllPositionv2();
+    JSONArray mainSearch(JSONObject params);
 
-    JSONObject handleAllPositionV2();
+    void syncData(String startTime, String endTime, String pageSize);
 }

+ 60 - 0
src/main/java/top/lvzhiqiang/service/impl/CoinApiConfigServiceImpl.java

@@ -0,0 +1,60 @@
+package top.lvzhiqiang.service.impl;
+
+import org.springframework.stereotype.Service;
+import top.lvzhiqiang.entity.CoinApiConfig;
+import top.lvzhiqiang.mapper.CoinApiConfigMapper;
+import top.lvzhiqiang.service.CoinApiConfigService;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * coin-API-配置ServiceImpl
+ *
+ * @author lvzhiqiang
+ * 2023/9/9 17:37
+ */
+@Service
+public class CoinApiConfigServiceImpl implements CoinApiConfigService {
+
+    @Resource
+    private CoinApiConfigMapper coinApiConfigMapper;
+
+    /**
+     * 删除所有
+     */
+    @Override
+    public void deleteAll() {
+        coinApiConfigMapper.deleteAll();
+    }
+
+    /**
+     * 批量新增
+     *
+     * @return
+     */
+    @Override
+    public void insertList(List<CoinApiConfig> coinApiConfigList) {
+        coinApiConfigMapper.insertList(coinApiConfigList);
+    }
+
+    /**
+     * 查询所有
+     *
+     * @return
+     */
+    @Override
+    public List<CoinApiConfig> findAll() {
+        return coinApiConfigMapper.findAll();
+    }
+
+    /**
+     * 多参数查询
+     *
+     * @return
+     */
+    @Override
+    public List<CoinApiConfig> findByParams(String nameCn, String url, Integer type, Integer type2, Integer status) {
+        return coinApiConfigMapper.findByParams(nameCn, url, type, type2, status);
+    }
+}

+ 177 - 75
src/main/java/top/lvzhiqiang/service/impl/CoinServiceImpl.java

@@ -4,17 +4,31 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import lombok.extern.slf4j.Slf4j;
 import org.jsoup.Connection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import top.lvzhiqiang.config.WorkWeixinProperties;
+import top.lvzhiqiang.entity.CoinHistoryOrder;
+import top.lvzhiqiang.mapper.CoinMapper;
 import top.lvzhiqiang.service.CoinService;
 import top.lvzhiqiang.util.CheckSign4Bitget;
 import top.lvzhiqiang.util.DateUtils;
 import top.lvzhiqiang.util.JsoupUtil;
 
+import javax.annotation.Resource;
 import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.InetSocketAddress;
 import java.net.Proxy;
 import java.security.InvalidKeyException;
-import java.util.HashMap;
-import java.util.Map;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 
 /**
  * Coin ServiceImpl
@@ -32,6 +46,16 @@ public class CoinServiceImpl implements CoinService {
     // 私钥,由系统随机生成,用于签名的生成。
     private static final String secretKey = "1fdd0fc2976bea80189ba13710e12825ca3ef6c5e25a0d76fd03f8f6cd4a61d9";
 
+    @Resource
+    private CoinMapper coinMapper;
+
+    @Autowired(required = false)
+    private WxCpService wxCpService;
+    @Autowired(required = false)
+    private WorkWeixinProperties properties;
+
+    private final Map<String, String> orderMap = new ConcurrentHashMap<>();
+
     static {
         // API KEY作为一个字符串。
         basicHeaderMap.put("ACCESS-KEY", "bg_433d37306df0e8901c6d107c6d9e9111");
@@ -47,90 +71,97 @@ public class CoinServiceImpl implements CoinService {
         basicHeaderMap.put("locale", "zh-CN");
     }
 
+    @Override
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+    public void syncData(String startTime, String endTime, String pageSize) {
+        // 获取全部历史委托
+        Map<String, String> paramMap = new LinkedHashMap<>();
+        paramMap.put("productType", "umcbl");
+        paramMap.put("startTime", startTime);
+        paramMap.put("endTime", endTime);
+        paramMap.put("pageSize", pageSize);
+
+        String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
+
+        JSONObject response = requestApi4Common("/api/mix/v1/order/historyProductType", signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
+
+        JSONArray orderList = response.getJSONObject("data").getJSONArray("orderList");
+        coinMapper.insertHistoryOrderList(JSONArray.parseArray(orderList.toJSONString(), CoinHistoryOrder.class));
+    }
+
 
     @Override
+    //@Async("coinTaskExecutor")
     public String monitorJob() {
+        Timer timer = new Timer();
+        timer.scheduleAtFixedRate(new TimerTask() {
+            @Override
+            public void run() {
+                // 全部历史委托监控
+                Map<String, String> paramMap = new LinkedHashMap<>();
+                paramMap.put("productType", "umcbl");
+                paramMap.put("startTime", String.valueOf(DateUtils.localDateTimeToMilliseconds(LocalDateTime.now().minusSeconds(10))));
+                paramMap.put("endTime", String.valueOf(System.currentTimeMillis()));
+                paramMap.put("pageSize", "100");
+
+                String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
+                JSONObject response = requestApi4Common("/api/mix/v1/order/historyProductType", signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
+                JSONArray orderList = response.getJSONObject("data").getJSONArray("orderList");
+
+                System.out.println(LocalDateTime.now() + ":" + orderList.size());
+                for (int i = 0; i < orderList.size(); i++) {
+                    JSONObject order = orderList.getJSONObject(i);
+                    LocalDateTime cTime = DateUtils.longToLocalDateTime(order.getLong("cTime"));
+                    String orderId = order.getString("orderId");
+                    if (Duration.between(cTime, LocalDateTime.now()).getSeconds() < 5 && !orderMap.containsKey(order.getString("orderId"))) {
+                        orderMap.put(orderId, "1");
+                        monitorAlarm(order);
+                    }
+                }
+            }
+        }, 0, 2000);
+
+        try {
+            Thread.sleep(100000);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
 
         return null;
     }
 
-    /**
-     * 获取全部合约仓位信息V2
-     *
-     * @author lvzhiqiang
-     * 2023/9/5 15:23
-     */
     @Override
-    public String findAllPositionv2() {
-        JSONObject result = handleAllPositionV2();
-        JSONArray data = result.getJSONArray("data");
-
-        StringBuffer sb = new StringBuffer("total:".concat(String.valueOf(data.size())).concat("<br/>"));
-        sb.append("<table border=\"1\" cellspacing=\"0\"><tr>");
-        sb.append("<th>币对名称</th>");
-        sb.append("<th>保证金币种</th>");
-        sb.append("<th>持仓方向</th>");
-        sb.append("<th>当前委托待成交的数量</th>");
-        sb.append("<th>保证金数量</th>");
-        sb.append("<th>自动追加保证金</th>");
-        sb.append("<th>仓位可用</th>");
-        sb.append("<th>仓位冻结</th>");
-        sb.append("<th>仓位总数量</th>");
-        sb.append("<th>杠杆倍数</th>");
-        sb.append("<th>已实现盈亏</th>");
-        sb.append("<th>平均开仓价</th>");
-        sb.append("<th>保证金模式</th>");
-        sb.append("<th>持仓模式</th>");
-        sb.append("<th>未实现盈亏</th>");
-        sb.append("<th>预估强平价</th>");
-        sb.append("<th>维持保证金率</th>");
-        sb.append("<th>标记价格</th>");
-        sb.append("<th>最近更新时间</th>");
-        sb.append("</tr>");
-
-        for (int i = 0; i < data.size(); i++) {
-            JSONObject jsonObject = data.getJSONObject(i);
-            sb.append("<tr>");
-
-            sb.append("<td>").append(jsonObject.getString("symbol")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("marginCoin")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("holdSide")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("openDelegateCount")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("margin")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("autoMargin")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("available")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("locked")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("total")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("leverage")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("achievedProfits")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("averageOpenPrice")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("marginMode")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("holdMode")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("unrealizedPL")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("liquidationPrice")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("keepMarginRate")).append("</td>");
-            sb.append("<td>").append(jsonObject.getString("marketPrice")).append("</td>");
-            sb.append("<td>").append(DateUtils.timeToString(jsonObject.getLong("cTime"))).append("</td>");
-
-            sb.append("</tr>");
-        }
-        sb.append("</table>");
+    @Async("coinTaskExecutor")
+    public void monitorAlarm(JSONObject order) {
+        String title = "监控告警明细";
+        String content = order.getString("symbol") + "触发";
+        String logUrl = "https://lvzhiqiang.top";
+        String btnTxt = "日志详情";
 
-        return sb.toString();
+        WxCpMessage wxCpMessage = WxCpMessage.TEXTCARD().agentId(properties.getAgentId())
+                .toUser("LvZhiQiang")
+                .toParty("")
+                .toTag("")
+                .title(title).description(content)
+                .url(logUrl).btnTxt(btnTxt)
+                .build();
+        try {
+            WxCpMessageSendResult sendResult = wxCpService.getMessageService().send(wxCpMessage);
+            System.out.println(sendResult);
+        } catch (WxErrorException e) {
+        }
     }
 
     /**
-     * 处理全部合约仓位信息V2
+     * 请求通用API方法
      */
-    @Override
-    public JSONObject handleAllPositionV2() {
-        String requestPath = "/api/mix/v1/position/allPosition-v2";
+    private JSONObject requestApi4Common(String requestPath, String signQueryString, String signBody, String httpMethod, Map<String, String> paramMap) {
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String queryString = "productType=umcbl";
+
         Map<String, String> headerMap = new HashMap<>();
         headerMap.putAll(basicHeaderMap);
         try {
-            String accessSign = CheckSign4Bitget.generate(timestamp, "GET", requestPath, queryString, null, secretKey);
+            String accessSign = CheckSign4Bitget.generate(timestamp, "GET", requestPath, signQueryString, signBody, secretKey);
             headerMap.put("ACCESS-TIMESTAMP", timestamp);
             headerMap.put("ACCESS-SIGN", accessSign);
         } catch (CloneNotSupportedException e) {
@@ -141,13 +172,11 @@ public class CoinServiceImpl implements CoinService {
             throw new RuntimeException(e);
         }
 
-        Map<String, String> paramMap = new HashMap<>();
-        paramMap.put("productType", "umcbl");
         try {
             String requestUrl = mainUrl + requestPath;
-            //Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 1080));
-            Proxy proxy = Proxy.NO_PROXY;
-            Connection.Response response = JsoupUtil.requestBody(requestUrl, JsoupUtil.HTTP_GET, proxy, headerMap, paramMap);
+            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 1080));
+            //Proxy proxy = Proxy.NO_PROXY;
+            Connection.Response response = JsoupUtil.requestBody(requestUrl, httpMethod, proxy, headerMap, paramMap);
 
             return JSONObject.parseObject(response.body());
         } catch (Exception e) {
@@ -155,8 +184,81 @@ public class CoinServiceImpl implements CoinService {
         }
     }
 
+    @Override
+    public JSONArray mainSearch(JSONObject params) {
+        JSONArray result = new JSONArray();
+        if (params.getString("nameEn").equals("allPositionv2")) {
+            Map<String, String> paramMap = new HashMap<>();
+            paramMap.put("productType", "umcbl");
+
+            String signQueryString = "productType=umcbl";
+
+            JSONObject response = requestApi4Common(params.getString("url"), signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
+
+            result = response.getJSONArray("data");
+
+            renderMainSearch4AllPositionv2(result);
+        } else if (params.getString("nameEn").equals("orderMarginCoinCurrent")) {
+            Map<String, String> paramMap = new LinkedHashMap<>();
+            paramMap.put("productType", "umcbl");
+            paramMap.put("marginCoin", "USDT");
+
+            String signQueryString = "productType=umcbl&marginCoin=USDT";
+
+            JSONObject response = requestApi4Common(params.getString("url"), signQueryString, null, JsoupUtil.HTTP_GET, paramMap);
+
+            result = response.getJSONArray("data");
+
+            renderMainSearch4OrderMarginCoinCurrent(result);
+        }
+
+        return result;
+    }
+
+    private void renderMainSearch4OrderMarginCoinCurrent(JSONArray result) {
+        for (int i = 0; i < result.size(); i++) {
+            JSONObject jsonObject = result.getJSONObject(i);
+
+            jsonObject.put("orderType", jsonObject.getString("orderType").equals("limit") ? "限价" : "市价");
+            jsonObject.put("marginMode", jsonObject.getString("marginMode").equals("fixed") ? "逐仓" : "全仓");
+
+            jsonObject.put("cTime", DateUtils.longToString(jsonObject.getLong("cTime")));
+            jsonObject.put("uTime", DateUtils.longToString(jsonObject.getLong("uTime")));
+        }
+    }
+
+    private void renderMainSearch4AllPositionv2(JSONArray result) {
+        for (int i = 0; i < result.size(); i++) {
+            JSONObject jsonObject = result.getJSONObject(i);
+            jsonObject.put("cTime", DateUtils.longToString(jsonObject.getLong("cTime")));
+            jsonObject.put("margin", new BigDecimal(jsonObject.getString("margin")).setScale(4, RoundingMode.HALF_UP));
+            jsonObject.put("averageOpenPrice", new BigDecimal(jsonObject.getString("averageOpenPrice")).setScale(4, RoundingMode.HALF_UP));
+            jsonObject.put("unrealizedPL", new BigDecimal(jsonObject.getString("unrealizedPL")).setScale(4, RoundingMode.HALF_UP));
+            jsonObject.put("liquidationPrice", new BigDecimal(jsonObject.getString("liquidationPrice")).setScale(4, RoundingMode.HALF_UP));
+
+            //未实现盈亏
+            if (jsonObject.getBigDecimal("unrealizedPL").compareTo(BigDecimal.ZERO) < 0) {
+                jsonObject.put("unrealizedPLStyle", " style=\"color:#FFFFFF;background-color:#F1493F;\"");
+            } else {
+                jsonObject.put("unrealizedPLStyle", " style=\"color:#FFFFFF;background-color:#1DA2B4;\"");
+            }
+            //标记价格
+            jsonObject.put("marketPriceStyle", " style=\"color:#252B31;background-color:#C4ADE9;font-weight:bold;\"");
+            //币对名称
+            String symbol = jsonObject.getString("symbol").replace("USDT_UMCBL", "");
+            jsonObject.put("symbol", "<strong style=\"background-color:#F1B90d;\"><font color=\"#242A30\">" + symbol + "</font></strong>USDT_UMCBL");
+        }
+    }
+
     public static void main(String[] args) {
         CoinServiceImpl coinService = new CoinServiceImpl();
-        System.out.println(coinService.handleAllPositionV2());
+        JSONObject params = new JSONObject();
+        /*params.put("nameEn", "allPositionv2");
+        params.put("url", "/api/mix/v1/position/allPosition-v2");*/
+
+        /*params.put("nameEn", "orderMarginCoinCurrent");
+        params.put("url", "/api/mix/v1/order/marginCoinCurrent");*/
+
+        System.out.println(coinService.mainSearch(params));
     }
 }

+ 36 - 18
src/main/java/top/lvzhiqiang/util/DateUtils.java

@@ -12,6 +12,7 @@
  */
 package top.lvzhiqiang.util;
 
+import java.sql.Timestamp;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.time.Instant;
@@ -58,11 +59,11 @@ public class DateUtils {
     public static final DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
 
     /**
-     * @Title: getToday
-     * @Description: 获取今天的日期
      * @param @return 设定文件
      * @return Date 返回类型
      * @throws
+     * @Title: getToday
+     * @Description: 获取今天的日期
      * @author shiyong
      * @date 2017年8月24日 下午2:11:03
      */
@@ -73,13 +74,13 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: getYesterday
      * @Description: 获取昨天的日期
      * @author: 施勇
      * @date: 2019年1月17日 上午7:18:38
      * @param: @return
      * @return: Date
-     * @throws
      */
     public static Date getYesterday() {
         Calendar cal = Calendar.getInstance();
@@ -89,13 +90,13 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: getTomorrow
      * @Description: 获取明天的日期
      * @author: 施勇
      * @date: 2019年1月17日 上午7:19:28
      * @param: @return
      * @return: Date
-     * @throws
      */
     public static Date getTomorrow() {
         Calendar cal = Calendar.getInstance();
@@ -105,6 +106,7 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: getTodayStr
      * @Description: 获取今天的日期字符串
      * @author: 施勇
@@ -112,7 +114,6 @@ public class DateUtils {
      * @param: @param pattern
      * @param: @return
      * @return: String
-     * @throws
      */
     public static String getTodayStr(String pattern) {
         SimpleDateFormat format = new SimpleDateFormat(pattern);
@@ -121,13 +122,13 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: getTodayStr
      * @Description: 获取今天的日期字符串
      * @author: 施勇
      * @date: 2019年1月17日 上午7:33:22
      * @param: @return
      * @return: String
-     * @throws
      */
     public static String getTodayStr() {
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
@@ -136,13 +137,13 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: getYesterdayStr
      * @Description: 获取昨天的日期字符串
      * @author: 施勇
      * @date: 2019年1月17日 上午7:21:11
      * @param: @return
      * @return: String
-     * @throws
      */
     public static String getYesterdayStr() {
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
@@ -151,13 +152,13 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: getTomorrowStr
      * @Description: 获取明天的日期字符串
      * @author: 施勇
      * @date: 2019年1月17日 上午7:25:00
      * @param: @return
      * @return: String
-     * @throws
      */
     public static String getTomorrowStr() {
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
@@ -166,6 +167,7 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: formatDate
      * @Description: 格式化日期
      * @author: 施勇
@@ -174,7 +176,6 @@ public class DateUtils {
      * @param: @param date
      * @param: @return
      * @return: String
-     * @throws
      */
     public static String formatDate(Date date) {
         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@@ -187,6 +188,7 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: formatDateTime
      * @Description: 格式化整个日期时间
      * @author: 施勇
@@ -194,7 +196,6 @@ public class DateUtils {
      * @param: @param date
      * @param: @return
      * @return: String
-     * @throws
      */
     public static String formatDateTime(Date date) {
         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -207,6 +208,7 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: parseDate
      * @Description: 格式化日期字符串
      * @author: 施勇
@@ -215,7 +217,6 @@ public class DateUtils {
      * @param: @return
      * @param: @throws ParseException
      * @return: Date
-     * @throws
      */
     public static Date parseDate(String dateString) throws ParseException {
         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@@ -224,6 +225,7 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: parseDateTime
      * @Description: 格式化时间字符串
      * @author: 施勇
@@ -232,7 +234,6 @@ public class DateUtils {
      * @param: @return
      * @param: @throws ParseException
      * @return: Date
-     * @throws
      */
     public static Date parseDateTime(String dateString) throws ParseException {
         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -241,6 +242,7 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: getFewDateStrsByDate
      * @Description: 获取近几天的日期字符串
      * @author: 施勇
@@ -249,7 +251,6 @@ public class DateUtils {
      * @param: @param num
      * @param: @return
      * @return: String
-     * @throws
      */
     public static String getFewDateStrsByDate(Date date, int num) {
         StringBuffer str = new StringBuffer();
@@ -273,6 +274,7 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: getFewDateStrsByWeek
      * @Description: 获取近几周同一天的日期字符串
      * @author: 施勇
@@ -281,7 +283,6 @@ public class DateUtils {
      * @param: @param num
      * @param: @return
      * @return: String
-     * @throws
      */
     public static String getFewDateStrsByWeek(Date date, int num) {
         StringBuffer str = new StringBuffer();
@@ -305,6 +306,7 @@ public class DateUtils {
     }
 
     /**
+     * @throws
      * @Title: getFewDateStrsByMonth
      * @Description: 获取近几月同一天的日期字符串
      * @author: 施勇
@@ -313,7 +315,6 @@ public class DateUtils {
      * @param: @param num
      * @param: @return
      * @return: String
-     * @throws
      */
     public static String getFewDateStrsByMonth(Date date, int num) {
         StringBuffer str = new StringBuffer();
@@ -338,9 +339,10 @@ public class DateUtils {
 
     /**
      * 获取时间戳
+     *
+     * @return long
      * @author shiyong
      * 2019-10-09 13:36
-     * @return long
      */
     public static long getTimeStamp() {
         return System.currentTimeMillis();
@@ -352,8 +354,24 @@ public class DateUtils {
      * @param time
      * @return
      */
-    public static String timeToString(Long time) {
-        return dateTimeFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));
+    public static String longToString(Long time) {
+        return dateTimeFormatter.format(longToLocalDateTime(time));
+    }
+
+    public static String longToString2(Long time) {
+        return dateFormatter.format(longToLocalDateTime(time));
+    }
+
+    public static LocalDateTime longToLocalDateTime(Long time) {
+        return LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault());
+    }
+
+    public static LocalDateTime longToLocalDateTime2(Long time) {
+        return new Timestamp(time).toLocalDateTime();
+    }
+
+    public static Long localDateTimeToMilliseconds(LocalDateTime time) {
+        return Timestamp.valueOf(time).getTime();
     }
 
     public static void main(String[] args) {

+ 9 - 1
src/main/resources/application.yml

@@ -35,4 +35,12 @@ pagehelper:
   helperDialect: mysql
   reasonable: true
   supportMethodsArguments: true
-  params: count=countSql
+  params: count=countSql
+
+# 企业微信
+work:
+  weixin:
+    enabled: true
+    corp-id: ww95a4adba56acb55f
+    agent-id: 1000002
+    secret: tqWepGSe91U2Cc2SDf2EGt6M2KaEy2PbvdEauGWywxs

+ 33 - 30
src/main/resources/static/coin.html

@@ -19,7 +19,7 @@
     }
 
     .dynamic_hide {
-        display: none;
+        display: block;
     }
 </style>
 <script type="text/javascript">
@@ -37,40 +37,43 @@
 <span>Hello <font id="myc" style="cursor: pointer;" onclick="show()">W</font>orld!</span>
 <div id="my" class="dynamic_hide">
     <hr/>
-    <div style="margin-right:20px;">
-        <span class="font aaa">获取全部合约仓位信息V2</span>
-        <button id="findAllPositionv2-1">展开</button>
-        <button id="findAllPositionv2-2">实时启动</button>
-        <button id="findAllPositionv2-3">实时停止</button>
-        <input type="text" style="width: 100px;" class="bbb">
+    <div style="display: flex;">
+        <select id="apis-move-select" style="height: 24px;margin-right: 10px;" class="font">
+        </select>
+        <div id="apis-move-div">
+            <button class = "apis-move-div-button1" slideDiv="apis-move-content">展开</button>
+            <button class="apis-move-div-button2" slideDiv="apis-move-content">实时启动</button>
+            <button class="apis-move-div-button3">实时停止</button>
+            <input type="text" style="width: 100px;padding-top: 3px;" class="apis-move-div-input1">
+        </div>
     </div>
-    <div id="content" style="display: none;">
-        total:<span id="contentSPAN">0</span>
+    <div id="apis-move-content" style="display: none;">
+        total:<span class="contentSPAN">0</span>
         <table border="1" cellspacing="0">
             <thead>
-                <tr id="contentTH">
-                    <th ccc="symbol">币对名称</th>
-                    <th ccc="marginCoin">保证金币种</th>
-                    <th ccc="holdSide">持仓方向</th>
-                    <th ccc="openDelegateCount">当前委托待成交的数量</th>
-                    <th ccc="margin">保证金数量</th>
-                    <th ccc="autoMargin">自动追加保证金</th>
-                    <th ccc="available">仓位可用</th>
-                    <th ccc="locked">仓位冻结</th>
-                    <th ccc="total">仓位总数量</th>
-                    <th ccc="leverage">杠杆倍数</th>
-                    <th ccc="achievedProfits">已实现盈亏</th>
-                    <th ccc="averageOpenPrice">平均开仓价</th>
-                    <th ccc="marginMode">保证金模式</th>
-                    <th ccc="holdMode">持仓模式</th>
-                    <th ccc="unrealizedPL">未实现盈亏</th>
-                    <th ccc="liquidationPrice">预估强平价</th>
-                    <th ccc="keepMarginRate">维持保证金率</th>
-                    <th ccc="marketPrice">标记价格</th>
-                    <th ccc="cTime">最近更新时间</th>
+                <tr class="contentTH">
                 </tr>
+                </thead>
+                <tbody class="contentTD">
+                </tbody>
+            </table>
+    </div>
+    <hr/>
+    <div style="display: flex;">
+        <select id="apis-quiet-select"  style="height: 24px;margin-right: 10px;" class="font aaa">
+        </select>
+        <div id="apis-quiet-div">
+            <button class="apis-quiet-div-button1" slideDiv="apis-quiet-content">展开</button>
+        </div>
+    </div>
+    <div id="apis-quiet-content" style="display: none;">
+        total:<span class="contentSPAN">0</span>
+        <table border="1" cellspacing="0">
+            <thead>
+            <tr class="contentTH">
+            </tr>
             </thead>
-            <tbody id="contentTD">
+            <tbody class="contentTD">
             </tbody>
         </table>
     </div>

+ 117 - 58
src/main/resources/static/js/my-coin.js

@@ -1,4 +1,6 @@
 window.cccField = '';
+window.apisMoveDivButton2Timer;
+window.actualFlag = false;
 
 $(function () {
     initOther();
@@ -8,38 +10,114 @@ $(function () {
  * 初始化其他操作
  */
 function initOther() {
-    $("#findAllPositionv2-1").click(function () {
-        var display = $('#content');
+    initOther4Select();
+    handleSelectChange($("select#apis-move-select,select#apis-quiet-select"));
+
+    $(".apis-move-div-button1,.apis-quiet-div-button1").click(function () {
+        var aa = $(this).attr("slideDiv");
+        var display = $('#' + aa);
         if (display.css('display') == 'block') {
             display.slideUp("slow");
+            //display.css("display", "none");
             $(this).html('展开');
         } else {
             display.slideDown("slow");
+            //display.css("display", "block");
             $(this).html('收起');
         }
     });
 
-    var findAllPositionv22Timer;
-    var actualFlag = false;
-    $("#findAllPositionv2-2").click(function () {
+
+    $(".apis-move-div-button2").click(function () {
         if (!actualFlag) {
-            findAllPositionv22Timer = setInterval("searchAllPositionv2()", "2000");
+            var selectedOption = $("select#apis-move-select").find("option:selected");
+            var url = selectedOption.attr("url");
+            var nameEn = selectedOption.attr("nameEn");
+
+            var slideDiv = $(this).attr("slideDiv");
+
+            apisMoveDivButton2Timer = setInterval(mainSearch, 2000, url, nameEn, slideDiv);
             actualFlag = true;
         }
     });
 
-    $("#findAllPositionv2-3").click(function () {
-        if (actualFlag) {
-            clearInterval(findAllPositionv22Timer);
-            actualFlag = false;
+    $(".apis-move-div-button3").click(function () {
+        ownClearInterval();
+    });
+}
+
+function ownClearInterval() {
+    if (actualFlag) {
+        clearInterval(apisMoveDivButton2Timer);
+        actualFlag = false;
+    }
+}
+
+function initOther4Select() {
+    $.ajax({
+        url: "coin/findApiConfig", //请求的url地址
+        dataType: "json", //返回格式为json
+        type: "post", //请求方式
+        contentType: "application/json;charset=utf-8",
+        async: false, //请求是否异步,默认为异步,这也是ajax重要特性
+        success: function (data) {
+            //请求成功时处理
+            if (data != null && $.trim(data) != "" && data.success) {
+                data = data.data
+
+                var quietStr = '';
+                var moveStr = '';
+                $.each(data, function (index, obj) {
+                    if (obj.type2 === 1) {
+                        moveStr += '<option nameEn="' + obj.nameEn + '" url="' + obj.url + '" returnEn="' + obj.returnEn + '" returnCn="' + obj.returnCn + '" value="' + obj.nameEn + '-option">' + obj.nameCn + '</option>';
+                    } else if (obj.type2 === 2) {
+                        quietStr += '<option nameEn="' + obj.nameEn + '" url="' + obj.url + '" returnEn="' + obj.returnEn + '" returnCn="' + obj.returnCn + '" value="' + obj.nameEn + '-option">' + obj.nameCn + '</option>';
+                    }
+                });
+
+                $("select#apis-move-select").html(moveStr);
+                $("select#apis-quiet-select").html(quietStr);
+
+                $("select#apis-move-select,select#apis-quiet-select").change(function () {
+                    handleSelectChange($(this));
+                });
+            } else {
+                //alert(data.message);
+            }
+        },
+        beforeSend: function () {
+        },
+        complete: function () {
+        },
+        error: function (data) {
+            //请求出错处理
+            //alert('error:' + data);
         }
     });
+}
 
-    $("#contentTH").find("th").dblclick(function () {
-        cccField = $(this).attr("ccc");
+function handleSelectChange(objj) {
+    $.each(objj, function (index, obj) {
+        var selectedOption = $(obj).find("option:selected");
+        var returnEn = selectedOption.attr("returnen").split(",");
+        var returnCn = selectedOption.attr("returncn").split(",");
+
+        var theadStr = '';
+        $.each(returnEn, function (index, obj) {
+            theadStr += '<th returnEn="' + obj + '">' + returnCn[index] + '</th>';
+        });
+
+        $(obj).parent("div").next("div").find("span.contentSPAN").html('0');
+        $(obj).parent("div").next("div").find("tr.contentTH").html(theadStr);
+        $(obj).parent("div").next("div").find("tbody.contentTD").html('');
+
+        if ($(obj).attr("id") === 'apis-move-select') {
+            ownClearInterval();
+        }
     });
-    $(".aaa").dblclick(function () {
-        cccField = '';
+
+    $(objj).parent("div").next("div").find(".contentTH").find("th").dblclick(function () {
+        cccField = $(this).attr("returnEn");
     });
 }
 
@@ -47,10 +125,14 @@ function initOther() {
  * 多条件搜索
  * @param pageNo
  */
-function searchAllPositionv2() {
+function mainSearch(url, nameEn, slideDiv) {
     $.ajax({
-        url: "coin/findAllPositionv2", //请求的url地址
+        url: "coin/mainSearch", //请求的url地址
         dataType: "json", //返回格式为json
+        data: JSON.stringify({
+            "url": url,
+            "nameEn": nameEn
+        }), //参数值
         type: "post", //请求方式
         contentType: "application/json;charset=utf-8",
         async: true, //请求是否异步,默认为异步,这也是ajax重要特性
@@ -59,57 +141,34 @@ function searchAllPositionv2() {
             if (data != null && $.trim(data) != "" && data.success) {
 
                 data = data.data;
-                $("#contentSPAN").html(data.length);
+                $('#' + slideDiv).find("span.contentSPAN").html(data.length);
+
+                var selectedOption = $('option[nameen="' + nameEn + '"]');
+                var returnEn = selectedOption.attr("returnen").split(",");
+
                 var str = '';
                 var title = 'Coin主页|';
                 for (var i = 0; i < data.length; i++) {
                     var dataDetail = data[i];
 
-                    //未实现盈亏
-                    var unrealizedPL = dataDetail.unrealizedPL;
-                    var unrealizedPLStyle = '';
-                    if (unrealizedPL < 0) {
-                        unrealizedPLStyle = ' style="color:#FFFFFF;background-color:#F1493F;"';
-                    } else {
-                        unrealizedPLStyle = ' style="color:#FFFFFF;background-color:#1DA2B4;"';
+                    if (nameEn === 'allPositionv2') {
+                        var bbbField = $(".apis-move-div-input1").val();
+                        var symbol = dataDetail.symbol;
+                        if (cccField.length > 0 && bbbField.length > 0 && symbol.indexOf(bbbField) != -1) {
+                            title += bbbField + '|' + dataDetail[cccField];
+                            $("title").html(title);
+                        }
                     }
-                    //币对名称
-                    var symbol = dataDetail.symbol;
-
-
-                    var bbbField = $(".bbb").val();
-                    if (cccField.length > 0 && bbbField.length > 0 && symbol.indexOf(bbbField) != -1) {
-                        title += bbbField + '|' + dataDetail[cccField];
-                        $("title").html(title);
-                    }
-
-                    symbol = '<strong' + ' style="background-color:#F1B90d;"' + '><font color="#242A30">' + symbol.replace('USDT_UMCBL', '') + '</font></strong>' + 'USDT_UMCBL';
-                    //标记价格
-                    var marketPriceStyle = ' style="color:#252B31;background-color:#C4ADE9;font-weight:bold;"';
 
                     str += '<tr>';
-                    str += '<td>' + symbol + '</td>';
-                    str += '<td>' + dataDetail.marginCoin + '</td>';
-                    str += '<td>' + dataDetail.holdSide + '</td>';
-                    str += '<td>' + dataDetail.openDelegateCount + '</td>';
-                    str += '<td>' + dataDetail.margin + '</td>';
-                    str += '<td>' + dataDetail.autoMargin + '</td>';
-                    str += '<td>' + dataDetail.available + '</td>';
-                    str += '<td>' + dataDetail.locked + '</td>';
-                    str += '<td>' + dataDetail.total + '</td>';
-                    str += '<td>' + dataDetail.leverage + '</td>';
-                    str += '<td>' + dataDetail.achievedProfits + '</td>';
-                    str += '<td>' + dataDetail.averageOpenPrice + '</td>';
-                    str += '<td>' + dataDetail.marginMode + '</td>';
-                    str += '<td>' + dataDetail.holdMode + '</td>';
-                    str += '<td' + unrealizedPLStyle + '>' + dataDetail.unrealizedPL + '</td>';
-                    str += '<td>' + dataDetail.liquidationPrice + '</td>';
-                    str += '<td>' + dataDetail.keepMarginRate + '</td>';
-                    str += '<td' + marketPriceStyle + '>' + dataDetail.marketPrice + '</td>';
-                    str += '<td>' + dataDetail.cTime + '</td>';
+                    $.each(returnEn, function (index, obj) {
+                        var objStyle = dataDetail.hasOwnProperty(obj + 'Style') ? dataDetail[obj + 'Style'] : '';
+                        var objContent = dataDetail.hasOwnProperty(obj) ? dataDetail[obj] : '--';
+                        str += '<td' + objStyle + '>' + objContent + '</td>';
+                    });
                     str += '</tr>';
                 }
-                $("#contentTD").html(str);
+                $('#' + slideDiv).find(".contentTD").html(str);
 
                 initContentEvent();
             } else {
@@ -131,7 +190,7 @@ function searchAllPositionv2() {
  * 初始化主内容事件
  */
 function initContentEvent() {
-    if ($(".bbb").val().length === 0) {
+    if ($(".apis-move-div-input1").val().length === 0) {
         $("title").html('Coin主页');
     }
 }

+ 14 - 8
src/test/java/Test4.java

@@ -18,18 +18,24 @@
  * 3、刷票。很多投票的网页一个IP只允许投票一次,如果我们借助大量代理IP去投票,结果可想而知....
  */
 
-import top.lvzhiqiang.entity.VideoInfo;
-import top.lvzhiqiang.service.impl.BgServiceImpl;
+import top.lvzhiqiang.util.DateUtils;
+
+import java.time.LocalDateTime;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * 爬取网上免费代理IP,搭建自己的Ip池
  */
 public class Test4 {
     public static void main(String[] args) {
-        BgServiceImpl bgService = new BgServiceImpl();
-        VideoInfo vi = new VideoInfo();
-        vi.setName("欲情した接吻痴女の唾液交換ベロ舐めセックス 三上悠亜");
-        bgService.getMaleCast(vi);
-        System.out.println(vi);
+        Map<String, String> paramMap = new LinkedHashMap<>();
+        paramMap.put("productType", "umcbl");
+        paramMap.put("startTime", String.valueOf(DateUtils.localDateTimeToMilliseconds(LocalDateTime.now().minusMonths(1))));
+        paramMap.put("endTime", String.valueOf(System.currentTimeMillis()));
+        paramMap.put("pageSize","100");
+
+        String signQueryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
     }
-}
+}

+ 44 - 0
src/test/java/top/lvzhiqiang/TestCoin.java

@@ -0,0 +1,44 @@
+package top.lvzhiqiang;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import top.lvzhiqiang.service.CoinService;
+import top.lvzhiqiang.util.DateUtils;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+
+/**
+ * 单元测试类
+ *
+ * @author lvzhiqiang
+ * @since 11:19 2022/5/2
+ */
+@Slf4j
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(properties = {
+        "spring.profiles.active=dev",
+        "logging.level.top.lvzhiqiang=DEBUG"
+}
+)
+public class TestCoin {
+
+    @Resource
+    private CoinService coinService;
+
+    @Test
+    public void testSyncData() {
+        String startTime = String.valueOf(DateUtils.localDateTimeToMilliseconds(LocalDateTime.now().minusMonths(1)));
+        String endTime = String.valueOf(System.currentTimeMillis());
+        String pageSize = "5";
+        coinService.syncData(startTime, endTime, pageSize);
+    }
+
+    @Test
+    public void testMonitorJob() {
+        coinService.monitorJob();
+    }
+}