|
@@ -0,0 +1,248 @@
|
|
|
+package com.qizhen.healsphere.facade;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.qizhen.healsphere.common.util.BeanUtil;
|
|
|
+import com.qizhen.healsphere.repository.mapper.EpifluMapper;
|
|
|
+import com.qizhen.healsphere.repository.mapper.EpifluQueryMapper;
|
|
|
+import com.qizhen.healsphere.repository.mapper.entity.Isolate;
|
|
|
+import com.qizhen.healsphere.service.impl.IsolateServiceImpl;
|
|
|
+import com.qizhen.healsphere.web.dto.*;
|
|
|
+import com.qizhen.healsphere.web.param.*;
|
|
|
+import com.qizhen.healsphere.web.vo.InputVO;
|
|
|
+import org.apache.poi.util.StringUtil;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Description: 用户日志业务层
|
|
|
+ * @author: gaodm
|
|
|
+ * @time: 2018/8/6 9:11
|
|
|
+ */
|
|
|
+@Component
|
|
|
+public class IsolateFacade extends IsolateServiceImpl {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EpifluMapper epifluMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EpifluQueryMapper epifluQueryMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取参数
|
|
|
+ *
|
|
|
+ * @param inputVO
|
|
|
+ * @return List<GraphInfo>
|
|
|
+ */
|
|
|
+ public List<IsolateDTO> getIsolate(InputVO inputVO) {
|
|
|
+ List<IsolateDTO> resultList = new ArrayList<>();
|
|
|
+ if (StringUtil.isNotBlank(inputVO.getContinent())) {
|
|
|
+ List<Epiflu> subtypeContinent = getSubtypeContinent(inputVO.getContinent());
|
|
|
+ // 创建并填充DTO
|
|
|
+ IsolateDTO isolateDTO = new IsolateDTO();
|
|
|
+ isolateDTO.setEpifluentName("甲流");
|
|
|
+ boolean flag = StringUtil.isBlank(inputVO.getSubtype())
|
|
|
+ || subtypeContinent.stream()
|
|
|
+ .map(Epiflu::getSubtype)
|
|
|
+ .noneMatch(st -> Objects.equals(st, inputVO.getSubtype()));
|
|
|
+
|
|
|
+ if(flag){
|
|
|
+ return getIsolateDTOList(inputVO);
|
|
|
+ }
|
|
|
+ resultList.add(isolateDTO);
|
|
|
+ } else {
|
|
|
+ return getIsolateDTOList(inputVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ return resultList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<IsolateDTO> getIsolateDTOList(InputVO inputVO) {
|
|
|
+ List<GraphInfo> graphInfoList = this.selectGraphInfo(inputVO);
|
|
|
+
|
|
|
+ // 收集所有唯一的subtype
|
|
|
+ List<String> subtypes = graphInfoList.stream()
|
|
|
+ .map(GraphInfo::getSubtype)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (subtypes.isEmpty()) {
|
|
|
+ return Collections.emptyList(); // 根据实际需求返回适当值
|
|
|
+ }
|
|
|
+
|
|
|
+ // 批量查询所有相关的Isolate记录,按subtype和日期排序
|
|
|
+ List<Isolate> allIsolates = getBaseMapper().selectList(
|
|
|
+ new QueryWrapper<Isolate>()
|
|
|
+ .in("subtype", subtypes)
|
|
|
+ .orderByAsc("subtype", "collection_date")
|
|
|
+ );
|
|
|
+
|
|
|
+ // 按subtype分组,优化数据处理
|
|
|
+ Map<String, List<Isolate>> isolatesBySubtype = allIsolates.stream()
|
|
|
+ .collect(Collectors.groupingBy(Isolate::getSubtype));
|
|
|
+
|
|
|
+ List<IsolateDTO> resultList = new ArrayList<>();
|
|
|
+ // 定义日期格式
|
|
|
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
+
|
|
|
+ for (GraphInfo graphInfo : graphInfoList) {
|
|
|
+ String subtype = graphInfo.getSubtype();
|
|
|
+ List<Isolate> isolateList = isolatesBySubtype.getOrDefault(subtype, Collections.emptyList());
|
|
|
+
|
|
|
+ if (isolateList.isEmpty()) {
|
|
|
+ continue; // 跳过无数据的subtype
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理首个隔离信息
|
|
|
+ Isolate firstIsolate = isolateList.get(0);
|
|
|
+ String firstLocation = firstIsolate.getLocation() != null ? firstIsolate.getLocation() : "未知地区";
|
|
|
+ Date firstDate = firstIsolate.getCollectionDate();
|
|
|
+ // 格式化日期(处理空值)
|
|
|
+ String formattedDate = (firstDate != null) ? dateFormat.format(firstDate) : "未知日期";
|
|
|
+
|
|
|
+ // 收集传播地点(排除首个)
|
|
|
+ Set<String> propagationLocations = new LinkedHashSet<>();
|
|
|
+ for (int i = 1; i < isolateList.size(); i++) {
|
|
|
+ String location = isolateList.get(i).getLocation();
|
|
|
+ if (location != null) {
|
|
|
+ String lastSegment = getLastSegment(location);
|
|
|
+ propagationLocations.add(lastSegment);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String propagation = propagationLocations.isEmpty() ? "无" : String.join(",", propagationLocations);
|
|
|
+
|
|
|
+ // 构建分析文本
|
|
|
+ String analyse = String.format("%s首次爆发日期:%s在%s爆发,之后在%s传播。",
|
|
|
+ subtype, formattedDate, firstLocation, propagation);
|
|
|
+
|
|
|
+ // 创建并填充DTO
|
|
|
+ IsolateDTO isolateDTO = new IsolateDTO();
|
|
|
+ BeanUtil.copyProperties(graphInfo, isolateDTO);
|
|
|
+ isolateDTO.setEpifluentName("甲流");
|
|
|
+ isolateDTO.setSubtype(subtype);
|
|
|
+ isolateDTO.setCumulative(getCumulativeList(subtype));
|
|
|
+ isolateDTO.setAnalyse(analyse);
|
|
|
+ isolateDTO.setGeoInfoList(getGeoInfoList(inputVO,subtype));
|
|
|
+ resultList.add(isolateDTO);
|
|
|
+ }
|
|
|
+ return resultList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Map<String, Integer> 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, Integer> 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);
|
|
|
+ int percentage = (int) countInMonth / countInYear * 100;
|
|
|
+ cumulative.put(monthKey, (int) (Math.ceil(percentage * 10.0) / 10.0));
|
|
|
+ }
|
|
|
+ return cumulative;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<GeoInfo> getGeoInfoList(InputVO inputVO,String input) {
|
|
|
+
|
|
|
+ List<String> continentList = StringUtil.isBlank(inputVO.getContinent())
|
|
|
+ ? Arrays.asList("Asia", "Europe", "Africa", "North America", "South America", "Oceania")
|
|
|
+ : Collections.singletonList(inputVO.getContinent().trim());
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public List<Epiflu> getSubtypeContinent(String continent) {
|
|
|
+ QueryWrapper<Epiflu> wrapper = new QueryWrapper<>();
|
|
|
+ wrapper.select("subtype", "clade", "COUNT(*) AS count")
|
|
|
+ .eq("continent_location", continent)
|
|
|
+ .groupBy("subtype", "clade")
|
|
|
+ .orderByDesc("count");
|
|
|
+
|
|
|
+ return epifluMapper.selectList(wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取中国的病毒分布情况
|
|
|
+ *
|
|
|
+ * @param inputVO
|
|
|
+ * @return List<GraphInfo>
|
|
|
+ */
|
|
|
+ public List<IsolateDTO> getChinaIsolate(InputVO inputVO) {
|
|
|
+ List<IsolateDTO> resultList = new ArrayList<>();
|
|
|
+ if (StringUtil.isNotBlank(inputVO.getContinent())) {
|
|
|
+ List<Epiflu> subtypeContinent = getSubtypeContinent(inputVO.getContinent());
|
|
|
+ // 创建并填充DTO
|
|
|
+ IsolateDTO isolateDTO = new IsolateDTO();
|
|
|
+ isolateDTO.setEpifluentName("甲流");
|
|
|
+ boolean flag = StringUtil.isBlank(inputVO.getSubtype())
|
|
|
+ || subtypeContinent.stream()
|
|
|
+ .map(Epiflu::getSubtype)
|
|
|
+ .noneMatch(st -> Objects.equals(st, inputVO.getSubtype()));
|
|
|
+
|
|
|
+ if(flag){
|
|
|
+ return getIsolateDTOList(inputVO);
|
|
|
+ }
|
|
|
+ resultList.add(isolateDTO);
|
|
|
+ } else {
|
|
|
+ return getIsolateDTOList(inputVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ return resultList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String getLastSegment(String input) {
|
|
|
+ Pattern pattern = Pattern.compile(".*/([^/]+)/?");
|
|
|
+ Matcher matcher = pattern.matcher(input);
|
|
|
+ return matcher.find() ? matcher.group(1) : "";
|
|
|
+ }
|
|
|
+
|
|
|
+}
|