Explorar el Código

浙一项目二期————传染病可视化

chenbin hace 3 meses
padre
commit
71cdf76be4

+ 6 - 6
pom.xml

@@ -180,12 +180,12 @@
             <version>3.5.9</version>
         </dependency>
 
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-devtools</artifactId>
-            <scope>runtime</scope>
-            <optional>true</optional>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>org.springframework.boot</groupId>-->
+<!--            <artifactId>spring-boot-devtools</artifactId>-->
+<!--            <scope>runtime</scope>-->
+<!--            <optional>true</optional>-->
+<!--        </dependency>-->
 
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 45 - 0
src/main/java/com/qizhen/healsphere/repository/mapper/EpifluMapper.java

@@ -0,0 +1,45 @@
+package com.qizhen.healsphere.repository.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qizhen.healsphere.web.param.CladeCountResult;
+import com.qizhen.healsphere.web.param.Epiflu;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDate;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface EpifluMapper extends BaseMapper<Epiflu> {
+    //获取subtype的列表
+    @Select("SELECT DISTINCT subtype FROM epiflu")
+    List<String> findDistinctSubtype();
+    @Select("SELECT DISTINCT clade FROM epiflu WHERE subtype = #{subtype}")
+    List<String> findDistinctCladeBySubtype(@Param("subtype") String subtype);
+    @Select("SELECT COUNT(1) FROM epiflu WHERE subtype = #{subtype}")
+    Integer selectCountBySubtype(@Param("subtype") String subtype);
+
+    @Select("SELECT MAX(collection_date) FROM epiflu WHERE subtype = #{subtype}")
+    Date findMaxCollectionDateBySubtype(@Param("subtype") String subtype);
+
+    @Select("SELECT COUNT(1) FROM epiflu WHERE subtype = #{subtype} AND collection_date BETWEEN #{startDate} AND #{endDate}")
+    Integer selectCountBySubtypeAndDateRange(@Param("subtype") String subtype, @Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
+    @Select("SELECT COUNT(1) FROM epiflu WHERE subtype = #{subtype} AND collection_date BETWEEN #{startDate} AND #{endDate} AND location LIKE CONCAT('%', #{continent}, '%')")
+    Integer selectCountBySubtypeAndDateRangeWithContinent(@Param("subtype") String subtype, @Param("startDate") LocalDate SeasonStartDate, @Param("endDate") LocalDate SeasonEndDate, @Param("continent") String continent);
+
+    /**
+     * 查询指定洲的clade分布
+     * @param continent 洲名称
+     * @return clade统计列表
+     */
+    @Select("SELECT clade, COUNT(*) AS count " +
+            "FROM public.epiflu " +
+            "WHERE continent_location = #{continent} " +
+            "AND subtype = #{subtype} " +
+            "GROUP BY clade " +
+            "ORDER BY count DESC")
+    List<CladeCountResult> selectCladeCountByContinent(@Param("continent") String continent , @Param("subtype") String subType);
+}

+ 175 - 8
src/main/java/com/qizhen/healsphere/service/impl/ZYApiServiceImpl.java

@@ -1,17 +1,20 @@
 package com.qizhen.healsphere.service.impl;
 
 import com.qizhen.healsphere.repository.mapper.BacteriaGenusMapper;
+import com.qizhen.healsphere.repository.mapper.EpifluMapper;
 import com.qizhen.healsphere.repository.mapper.StrainMapper;
-import com.qizhen.healsphere.web.param.BacteriaGenus;
-import com.qizhen.healsphere.web.param.Strain;
+import com.qizhen.healsphere.web.param.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import java.time.LocalDate;
+import java.time.Year;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
 import java.util.stream.Collectors;
+
 @Slf4j
 @Service
 public class ZYApiServiceImpl {
@@ -22,6 +25,9 @@ public class ZYApiServiceImpl {
     @Autowired
     private StrainMapper strainMapper;
 
+    @Autowired
+    private EpifluMapper epifluMapper;
+
     public List<BacteriaGenus> getBacteriaInfo(String input) {
         log.info("Calling getBacteriaInfo with input: {}", input);
         // 将输入字符串按逗号分割成列表
@@ -29,10 +35,10 @@ public class ZYApiServiceImpl {
 
         // 查询 strain 表
         List<Strain> strains = strainMapper.findByParentNames(names);
-        List<String> pnames = strains.stream().map(Strain::getParentName).collect(Collectors.toList());    // 查询 bacteriagenus 表
-        List<BacteriaGenus> bacteriaGenera = bacteriaGenusMapper.findByGenericNames(pnames);
-
+        List<String> pnames = strains.stream().map(Strain::getParentName).collect(Collectors.toList());
 
+        // 查询 bacteriagenus 表
+        List<BacteriaGenus> bacteriaGenera = bacteriaGenusMapper.findByGenericNames(pnames);
 
         // 将 strains 按 parentName 分组
         Map<String, List<Strain>> strainMap = strains.stream()
@@ -48,4 +54,165 @@ public class ZYApiServiceImpl {
 
         return bacteriaGenera;
     }
+
+    public List<String> getCladeList(String subType) {
+        return epifluMapper.findDistinctCladeBySubtype(subType);
+    }
+
+    public Integer getCount(String subType) {
+        return epifluMapper.selectCountBySubtype(subType);
+    }
+
+    public Map<String,Double> getCumulativeList(String subtype) {
+        Date maxCollectionDate = epifluMapper.findMaxCollectionDateBySubtype(subtype);
+        // 更安全的日期转换方式
+        LocalDate startDate = maxCollectionDate.toInstant()
+                .atZone(ZoneId.of("UTC"))  // 明确指定时区为UTC
+                .toLocalDate()
+                .withDayOfYear(1);
+        LocalDate endDate = startDate.plusMonths(12).minusDays(1);
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+        Map<String, Double> cumulative = new TreeMap<>(); // 使用 TreeMap 保持键的有序性
+        for (int i = 0; i < 12; i++) {
+            LocalDate monthStartDate = startDate.plusMonths(i);
+            LocalDate monthEndDate = monthStartDate.plusMonths(1).minusDays(1);
+            String monthKey = monthStartDate.format(formatter);
+            //如果要把逻辑改成每个月占比,把下面的 startDate改成monthStartDate
+            int countInMonth = epifluMapper.selectCountBySubtypeAndDateRange(subtype, startDate, monthEndDate);
+            int countInYear = epifluMapper.selectCountBySubtypeAndDateRange(subtype, startDate, endDate);
+            double percentage = (double) countInMonth / countInYear * 100;
+            cumulative.put(monthKey, Math.round(percentage * 10.0) / 10.0); // 保留小数点后一位
+        }
+        return cumulative;
+    }
+//    public Map<String, Integer> getInEachContinentMap(String subtype) {
+//        List<String> continentList = Arrays.asList("Asia", "Europe", "Africa", "North America", "South America", "Oceania");
+//        Date maxCollectionDate = epifluMapper.findMaxCollectionDateBySubtype(subtype);
+//        // 更安全的日期转换方式
+//        LocalDate startDate = maxCollectionDate.toInstant()
+//                .atZone(ZoneId.of("UTC"))  // 明确指定时区为UTC
+//                .toLocalDate()
+//                .withDayOfYear(1);
+//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+//
+//        Map<String, Integer> inEachContinent = new TreeMap<>(); // 使用 TreeMap 保持键的有序性
+//        for (String continent : continentList) {
+//            for (int i = 0; i < 12; i+=3) {
+//                LocalDate SeasonStartDate = startDate.plusMonths(i);
+//                LocalDate seasonEndDate = SeasonStartDate.plusMonths(3).minusDays(1);
+//                String SeasonKey = SeasonStartDate.format(formatter);
+//                int counInSeason = epifluMapper.selectCountBySubtypeAndDateRangeWithContinent(subtype, SeasonStartDate, seasonEndDate, continent);
+//                inEachContinent.put(SeasonKey, counInSeason);
+//            }
+//        }
+//        return inEachContinent;
+//    }
+public Map<String, Object> getInEachContinentMap(String subtype) {
+    List<String> continentList = Arrays.asList("Asia", "Europe", "Africa",
+            "North America", "South America", "Oceania");
+    // 颜色数组
+    List<String> colors = Arrays.asList("#67a71f", "#e4ab04", "#7f79b7",
+            "#1a9e76", "#dc5d04", "#a5761a");
+
+    Date maxCollectionDate = epifluMapper.findMaxCollectionDateBySubtype(subtype);
+    LocalDate startDate = maxCollectionDate.toInstant()
+            .atZone(ZoneId.of("UTC"))
+            .toLocalDate()
+            .withDayOfYear(1);
+
+    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+    Map<String, Object> inEachContinent = new HashMap<>();
+
+    // 1. 准备x轴数据 - 所有季度标签
+    List<String> xAxis = new ArrayList<>();
+    for (String continent : continentList) {
+        for (int i = 0; i < 12; i += 3) {
+            LocalDate seasonStart = startDate.plusMonths(i);
+            xAxis.add(seasonStart.format(formatter));
+        }
+        xAxis.add(" "); // 每大洲后加空字符串
+    }
+    // 移除最后一个多余的空格
+    if (!xAxis.isEmpty() && xAxis.get(xAxis.size()-1).equals(" ")) {
+        xAxis.remove(xAxis.size() - 1);
+    }
+    inEachContinent.put("x", xAxis);
+
+    // 2. 准备y轴数据 - 改为List<Object>以支持混合类型
+    List<Object> yAxis = new ArrayList<>();
+    int colorIndex = 0;
+    int itemCount = 0;
+
+    for (String continent : continentList) {
+        for (int i = 0; i < 12; i += 3) {
+            LocalDate seasonStart = startDate.plusMonths(i);
+            LocalDate seasonEnd = seasonStart.plusMonths(3).minusDays(1);
+
+            int count = epifluMapper.selectCountBySubtypeAndDateRangeWithContinent(
+                    subtype, seasonStart, seasonEnd, continent);
+
+            Map<String, Object> dataItem = new HashMap<>();
+            dataItem.put("value", count);
+
+            Map<String, String> itemStyle = new HashMap<>();
+            itemStyle.put("color", colors.get(colorIndex));
+            dataItem.put("itemStyle", itemStyle);
+
+            yAxis.add(dataItem);
+            itemCount++;
+
+            // 每4个数据项后插入空字符串并切换颜色
+            if (itemCount % 4 == 0) {
+                yAxis.add(" "); // 插入空字符串分隔符
+                colorIndex = (colorIndex + 1) % colors.size();
+            }
+        }
+    }
+
+    // 移除最后可能多余的空字符串
+    if (!yAxis.isEmpty() && yAxis.get(yAxis.size()-1) instanceof String) {
+        yAxis.remove(yAxis.size() - 1);
+    }
+
+    inEachContinent.put("y", yAxis);
+    return inEachContinent;
 }
+
+    public List<GeoInfo> getGeoInfoList(String input) {
+        List<String> continentList = Arrays.asList("Asia", "Europe", "Africa",
+                "North America", "South America", "Oceania");
+        List<GeoInfo> geoInfoList = new ArrayList<>();
+
+        for (String continent : continentList) {
+            GeoInfo geoInfo = new GeoInfo();
+
+            // 1. 获取clade统计数据
+            List<CladeCountResult> cladeCountResult = epifluMapper.selectCladeCountByContinent(continent, input);
+
+            // 2. 转换数据格式
+            List<GeoDataItem> dataItems = cladeCountResult.stream()
+                    .map(result -> new GeoDataItem(result.getClade(), result.getCount()))
+                    .collect(Collectors.toList());
+
+            // 3. 设置中心坐标(注意这里传入的是Double数组)
+            ContinentCoordinates coordinates = ContinentCoordinates.fromName(continent.toUpperCase().replace(" ", "_"));
+            geoInfo.setContinentName(continent);
+            geoInfo.setCenter(new Double[]{
+                    Double.parseDouble(coordinates.getLongitude()),
+                    Double.parseDouble(coordinates.getLatitude())
+            });
+
+            // 4. 设置数据
+            geoInfo.setData(dataItems);
+
+            geoInfoList.add(geoInfo);
+        }
+
+        return geoInfoList;
+    }
+    //获取所有的subType值
+    public List<String> findDistinctSubtype(){
+        return epifluMapper.findDistinctSubtype();
+    }
+}

+ 21 - 1
src/main/java/com/qizhen/healsphere/web/ZYController.java

@@ -8,6 +8,8 @@ import com.qizhen.healsphere.service.impl.DepartmentServiceImpl;
 import com.qizhen.healsphere.service.impl.ZYApiServiceImpl;
 import com.qizhen.healsphere.web.param.BacteriaGenus;
 import com.qizhen.healsphere.web.param.DetailInfo;
+import com.qizhen.healsphere.web.param.GeoInfo;
+import com.qizhen.healsphere.web.param.GraphInfo;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
@@ -42,7 +44,6 @@ public class ZYController {
 
         return detailInfo;
     }
-
     /**
      * 获取解释信息并清洗
      *
@@ -129,4 +130,23 @@ public class ZYController {
         }
         return cleanedList;
     }
+    @PostMapping("/graph")
+    @ResponseBody
+    public List<GraphInfo> getGraphInfo() {
+        List<GraphInfo> graphInfoList = new ArrayList<>();
+        List<String> subTypeList = zyApiService.findDistinctSubtype();
+        for (String subType : subTypeList) {
+            GraphInfo graphInfo = new GraphInfo();
+            graphInfo.setClade(zyApiService.getCladeList(subType));
+            graphInfo.setSubtype(subType);
+            graphInfo.setCount(zyApiService.getCount(subType));
+            graphInfo.setCumulative(zyApiService.getCumulativeList(subType));
+            graphInfo.setInEachContinent(zyApiService.getInEachContinentMap(subType));
+            graphInfo.setGeoInfoList(zyApiService.getGeoInfoList(subType));
+            graphInfoList.add(graphInfo);
+        }
+        return graphInfoList;
+    }
+
+
 }

+ 19 - 0
src/main/java/com/qizhen/healsphere/web/param/CladeCountResult.java

@@ -0,0 +1,19 @@
+package com.qizhen.healsphere.web.param;
+
+import lombok.Data;
+
+/**
+ * Clade统计查询结果
+ */
+@Data
+public class CladeCountResult {
+    /**
+     * Clade名称
+     */
+    private String clade;
+
+    /**
+     * 计数结果
+     */
+    private Integer count;
+}

+ 45 - 0
src/main/java/com/qizhen/healsphere/web/param/ContinentCoordinates.java

@@ -0,0 +1,45 @@
+package com.qizhen.healsphere.web.param;
+
+public enum ContinentCoordinates {
+    ASIA("+43.000000", "+87.000000"),
+    EUROPE("+45.000000", "+10.000000"),
+    AFRICA("+3.000000", "+23.000000"),
+    OCEANIA("-24.000000", "+135.000000"),
+    NORTH_AMERICA("+45.000000", "-100.000000"),
+    SOUTH_AMERICA("-15.000000", "-65.000000");
+
+    private final String latitude;
+    private final String longitude;
+
+    // 构造函数
+    ContinentCoordinates(String latitude, String longitude) {
+        this.latitude = latitude;
+        this.longitude = longitude;
+    }
+
+    // 获取纬度
+    public String getLatitude() {
+        return latitude;
+    }
+
+    // 获取经度
+    public String getLongitude() {
+        return longitude;
+    }
+
+    // 根据大洲名称获取枚举实例
+    public static ContinentCoordinates fromName(String name) {
+        for (ContinentCoordinates continent : ContinentCoordinates.values()) {
+            if (continent.name().equalsIgnoreCase(name)) {
+                return continent;
+            }
+        }
+        throw new IllegalArgumentException("Unknown continent: " + name);
+    }
+
+    // 重写 toString 方法,方便打印
+    @Override
+    public String toString() {
+        return name() + " - Latitude: " + latitude + ", Longitude: " + longitude;
+    }
+}

+ 7 - 0
src/main/java/com/qizhen/healsphere/web/param/CumulateGraph.java

@@ -0,0 +1,7 @@
+package com.qizhen.healsphere.web.param;
+
+import java.util.List;
+
+public class CumulateGraph {
+
+}

+ 13 - 0
src/main/java/com/qizhen/healsphere/web/param/Epiflu.java

@@ -0,0 +1,13 @@
+package com.qizhen.healsphere.web.param;
+
+import lombok.Data;
+
+import java.util.Date;
+@Data
+public class Epiflu {
+    private Date collectionDate;
+    private String location;
+    private String subtype;
+    private String clade;
+
+}

+ 13 - 0
src/main/java/com/qizhen/healsphere/web/param/GeoDataItem.java

@@ -0,0 +1,13 @@
+package com.qizhen.healsphere.web.param;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class GeoDataItem  {
+    private String name;
+    private Number value;
+}

+ 18 - 0
src/main/java/com/qizhen/healsphere/web/param/GeoInfo.java

@@ -0,0 +1,18 @@
+package com.qizhen.healsphere.web.param;
+
+import java.util.List;
+import lombok.Data;
+@Data
+public class GeoInfo {
+
+    private String continentName;
+    /**
+     * 地理中心点坐标 [经度, 纬度]
+     */
+    private Double[] center;
+
+    /**
+     * 该地理区域下的数据集合
+     */
+    private List<GeoDataItem> data;
+}

+ 16 - 0
src/main/java/com/qizhen/healsphere/web/param/GraphInfo.java

@@ -0,0 +1,16 @@
+package com.qizhen.healsphere.web.param;
+
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class GraphInfo {
+    private List<String> clade;
+    private String subtype;
+    private int Count;
+    private Map<String, Double> cumulative;
+    private Map<String, Object> inEachContinent;
+    private List<GeoInfo> geoInfoList;
+}