From 0b39edb68acc67ed01fbfe5d31bfa776a1b17de1 Mon Sep 17 00:00:00 2001
From: zxl <763096477@qq.com>
Date: 星期三, 25 三月 2026 09:14:53 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/show-demo' into show_demo

---
 jyz-base-start/src/main/java/com/tievd/jyz/service/IOilRecordService.java         |    4 
 jyz-base-start/src/main/java/com/tievd/jyz/controller/DataTableController.java    |   20 ++
 jyz-base-start/src/main/resources/xml/OilRecordMapper.xml                         |   48 +++++
 jyz-base-start/src/main/java/com/tievd/jyz/entity/Client.java                     |    3 
 jyz-base-start/src/main/java/com/tievd/jyz/entity/ClientConfig.java               |   16 +
 jyz-base-start/src/main/java/com/tievd/jyz/service/impl/OilRecordServiceImpl.java |  130 ++++++++++++++
 jyz-base-start/src/main/java/com/tievd/jyz/Timer/SystemSchedule.java              |  130 ++++++++++++--
 jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientConfigController.java |   82 ++++++++
 jyz-base-start/src/main/java/com/tievd/jyz/mapper/OilRecordMapper.java            |    2 
 jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientController.java       |   42 ++++
 jyz-base-start/src/main/java/com/tievd/jyz/entity/vo/DataStatisReqVo.java         |   18 ++
 11 files changed, 473 insertions(+), 22 deletions(-)

diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/Timer/SystemSchedule.java b/jyz-base-start/src/main/java/com/tievd/jyz/Timer/SystemSchedule.java
index 882d65e..46d93a7 100644
--- a/jyz-base-start/src/main/java/com/tievd/jyz/Timer/SystemSchedule.java
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/Timer/SystemSchedule.java
@@ -279,7 +279,13 @@
          */
         public String infer() {
             try {
+                if (CollectionUtils.isEmpty(rules.getClientConfigs())) {
+                    return null;
+                }
                 for (ClientConfig rule : rules.getClientConfigs()) {
+                    if (rule == null || rule.getTimeValue() == null || StringUtils.isBlank(rule.getTimeUnit())) {
+                        return null;
+                    }
                     ChronoUnit unit = ChronoUnit.valueOf(rule.getTimeUnit().toUpperCase());
                     LocalDate timeLimit = LocalDate.now().minus(rule.getTimeValue(), unit);
                     switch(unit) {
@@ -288,30 +294,53 @@
                     }
                     LocalDate finalTimeLimit = timeLimit;
                     List<T> filterData = dataList.stream().filter(t -> !timeVal.apply(t).isBefore(finalTimeLimit)).collect(Collectors.toList());
-                    int limit = rule.getCountNum();
-                    int ref = rule.getCountRef();
-                    if (rule.getCountType() == 1) {
-                        int sum = filterData.size();
-                        if (Integer.compare(sum, limit) != ref) {
+                    
+                    // 鏍规嵁瑙勫垯绫诲瀷閫夋嫨鍒ゆ柇閫昏緫
+                    Byte ruleType = rule.getRuleType();
+                    if (ruleType == null) {
+                        return null;
+                    }
+                    if (ruleType == 1) {
+                        if (rule.getCountType() == null || rule.getCountRef() == null || rule.getCountNum() == null) {
                             return null;
                         }
-                    } else if((rule.getCountType() == 2)) {
-                        Map<Integer, Integer> monthCount = new HashMap<>();
-                        int nowMonth = LocalDate.now().getMonthValue();
-                        for (int month = timeLimit.getMonthValue(); month != nowMonth ; month++) {
-                            monthCount.put(month, 0);
-                        }
-                        for (T tmp : filterData) {
-                            int month = timeVal.apply(tmp).getMonthValue();
-                            if (monthCount.containsKey(month)) {
-                                monthCount.put(month, monthCount.get(month) + 1);
+                        // 鍔犳补棰戞锛堝師鏈夐�昏緫锛�
+                        int limit = rule.getCountNum();
+                        int ref = rule.getCountRef();
+                        if (rule.getCountType() == 1) {
+                            int sum = filterData.size();
+                            if (Integer.compare(sum, limit) != ref) {
+                                return null;
                             }
-                        }
-                        Collection<Integer> countNums = monthCount.values();
-                        if (countNums.stream().anyMatch(n -> Integer.compare(n, limit) != ref)) {
+                        } else if((rule.getCountType() == 2)) {
+                            Map<Integer, Integer> monthCount = new HashMap<>();
+                            int nowMonth = LocalDate.now().getMonthValue();
+                            for (int month = timeLimit.getMonthValue(); month != nowMonth ; month++) {
+                                monthCount.put(month, 0);
+                            }
+                            for (T tmp : filterData) {
+                                int month = timeVal.apply(tmp).getMonthValue();
+                                if (monthCount.containsKey(month)) {
+                                    monthCount.put(month, monthCount.get(month) + 1);
+                                }
+                            }
+                            Collection<Integer> countNums = monthCount.values();
+                            if (countNums.stream().anyMatch(n -> Integer.compare(n, limit) != ref)) {
+                                return null;
+                            }
+                        } else {
                             return null;
                         }
-                        /////////////////////////////
+                    } else if (ruleType == 2) {
+                        // 鍔犳补瓒嬪娍锛堟柊閫昏緫锛�
+                        if (rule.getCountTrend() == null || rule.getCountNum() == null || rule.getHistoryMonths() == null || rule.getRecentMonths() == null) {
+                            return null;
+                        }
+                        if (!checkTrend(rule, filterData)) {
+                            return null;
+                        }
+                    } else {
+                        return null;
                     }
                 }
             } catch (Exception e) {
@@ -321,6 +350,69 @@
             return rules.getClientName();
         }
         
+        /**
+         * 瓒嬪娍鍒ゆ柇锛堜娇鐢ㄩ厤缃殑鏈堟暟锛�
+         * @param rule 瑙勫垯
+         * @param dataList 鏁版嵁鍒楄〃
+         * @return
+         */
+        private boolean checkTrend(ClientConfig rule, List<T> dataList) {
+            if (dataList == null || dataList.isEmpty()) {
+                return false;
+            }
+            
+            Byte countTrend = rule.getCountTrend();
+            Integer countNum = rule.getCountNum();
+            Integer historyMonths = rule.getHistoryMonths();
+            Integer recentMonths = rule.getRecentMonths();
+            if (countTrend == null || countNum == null || historyMonths == null || recentMonths == null) {
+                return false;
+            }
+            if (historyMonths <= 0 || recentMonths <= 0 || countNum <= 0) {
+                return false;
+            }
+            
+            LocalDate now = LocalDate.now();
+            LocalDate currentMonth = now.withDayOfMonth(1);
+            LocalDate recentStart = currentMonth.minusMonths(recentMonths - 1L);
+            LocalDate historyStart = recentStart.minusMonths(historyMonths);
+            LocalDate historyEnd = recentStart;
+            
+            Map<LocalDate, Integer> recentMonthCount = new LinkedHashMap<>();
+            for (int i = 0; i < recentMonths; i++) {
+                LocalDate month = recentStart.plusMonths(i);
+                recentMonthCount.put(month, 0);
+            }
+
+            Map<LocalDate, Integer> historyMonthCount = new LinkedHashMap<>();
+            for (int i = 0; i < historyMonths; i++) {
+                LocalDate month = historyStart.plusMonths(i);
+                historyMonthCount.put(month, 0);
+            }
+
+            for (T tmp : dataList) {
+                LocalDate month = timeVal.apply(tmp).withDayOfMonth(1);
+                if (recentMonthCount.containsKey(month)) {
+                    recentMonthCount.put(month, recentMonthCount.get(month) + 1);
+                }
+                if (historyMonthCount.containsKey(month) && !month.isBefore(historyStart) && month.isBefore(historyEnd)) {
+                    historyMonthCount.put(month, historyMonthCount.get(month) + 1);
+                }
+            }
+            
+            if (countTrend == 1) {
+                boolean historyStable = historyMonthCount.values().stream().allMatch(n -> n >= countNum);
+                boolean recentStable = recentMonthCount.values().stream().allMatch(n -> n >= countNum);
+                return historyStable && recentStable;
+            } else if (countTrend == 2) {
+                boolean historyStable = historyMonthCount.values().stream().allMatch(n -> n >= countNum);
+                boolean recentDecrease = recentMonthCount.values().stream().allMatch(n -> n < countNum);
+                return historyStable && recentDecrease;
+            }
+            
+            return false;
+        }
+        
     }
     
 }
diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientConfigController.java b/jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientConfigController.java
index b1e36a1..f15653e 100644
--- a/jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientConfigController.java
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientConfigController.java
@@ -5,21 +5,31 @@
 import com.tievd.cube.commons.annotations.DictApi;
 import com.tievd.cube.commons.base.CubeController;
 import com.tievd.cube.commons.base.Result;
+import com.tievd.cube.commons.constant.CacheConst;
+import com.tievd.cube.modules.system.entity.SysDictItem;
+import com.tievd.cube.modules.system.service.ISysDictItemService;
+import com.tievd.jyz.entity.Client;
 import com.tievd.jyz.entity.ClientConfig;
 import com.tievd.jyz.entity.vo.ClientVo;
 import com.tievd.jyz.service.IClientConfigService;
 import com.tievd.jyz.service.IClientService;
+import cn.dev33.satoken.stp.StpUtil;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
+import java.util.UUID;
 
 /**
  * ClientConfig
@@ -35,11 +45,16 @@
 @Tag(name = "瀹㈡埛瑙勫垯閰嶇疆")
 public class ClientConfigController extends CubeController<ClientConfig, IClientConfigService> {
 
+  private static final String DICT_ID = "1631109859116990466";
+  
   @Autowired
   private IClientConfigService clientConfigService;
   
   @Autowired
   IClientService clientService;
+  
+  @Autowired
+  private ISysDictItemService sysDictItemService;
   
   /**
    * 鍒嗛〉鍒楄〃鏌ヨ
@@ -54,10 +69,13 @@
   
   @AutoLog("ClientConfig-娣诲姞")
   @PostMapping("/add")
+  @Transactional(rollbackFor = Exception.class)
+  @CacheEvict(value = CacheConst.SYS_DICT_CACHE, allEntries = true)
   @Operation(summary = "娣诲姞瀹㈡埛瑙勫垯")
   public Result<?> add(@RequestBody ClientVo clientVo) {
     clientService.save(clientVo);
     clientConfigService.saveBatch(getConfig(clientVo));
+    syncDictItem(clientVo.getClientName(), clientVo.getId());
     return Result.ok();
   }
   
@@ -66,23 +84,73 @@
    */
   @AutoLog("ClientConfig-缂栬緫")
   @PutMapping("/edit")
+  @Transactional(rollbackFor = Exception.class)
+  @CacheEvict(value = CacheConst.SYS_DICT_CACHE, allEntries = true)
   @Operation(summary = "淇敼瀹㈡埛瑙勫垯")
   public Result<?> edit(@RequestBody ClientVo clientVo) {
     clientService.updateById(clientVo);
     clientConfigService.remove(new LambdaQueryWrapper<ClientConfig>().eq(ClientConfig::getClientId, clientVo.getId()));
     clientConfigService.saveBatch(getConfig(clientVo));
+    updateDictItem(clientVo.getClientName(), clientVo.getId());
     return Result.ok();
   }
   
   List<ClientConfig> getConfig(ClientVo clientVo) {
     List<ClientConfig> clientConfigs = clientVo.getClientConfigs();
+    if (clientConfigs == null || clientConfigs.isEmpty()) {
+      return Collections.emptyList();
+    }
     clientConfigs.forEach(c -> {
-      String[] param = c.getTimeStr().split(",");
+      if (StringUtils.hasText(c.getTimeStr())) {
+        String[] param = c.getTimeStr().split(",");
+        c.setTimeValue(Integer.valueOf(param[0])).setTimeUnit(param[1]);
+      }
+      if (c.getRuleType() == null) {
+        c.setRuleType((byte) 1);
+      }
+      if (c.getRuleType() == 2) {
+        if (c.getCountType() == null) {
+          c.setCountType((byte) 2);
+        }
+        if (c.getCountRef() == null) {
+          c.setCountRef((byte) 1);
+        }
+      }
       c.setClientId(clientVo.getId())
-              .setClientName(clientVo.getClientName())
-              .setTimeValue(Integer.valueOf(param[0])).setTimeUnit(param[1]);
+              .setClientName(clientVo.getClientName());
     });
     return clientConfigs;
+  }
+  
+  private void syncDictItem(String clientName, Integer clientId) {
+    SysDictItem dictItem = new SysDictItem();
+    dictItem.setId(UUID.randomUUID().toString().replace("-", ""));
+    dictItem.setDictId(DICT_ID);
+    dictItem.setItemText(clientName);
+    dictItem.setItemValue(String.valueOf(clientId));
+    dictItem.setSortOrder(clientId);
+    dictItem.setStatus(1);
+    dictItem.setCreateBy(StpUtil.getLoginIdAsString());
+    dictItem.setCreateTime(new java.util.Date());
+    sysDictItemService.save(dictItem);
+  }
+  
+  private void updateDictItem(String clientName, Integer clientId) {
+    LambdaQueryWrapper<SysDictItem> wrapper = new LambdaQueryWrapper<>();
+    wrapper.eq(SysDictItem::getDictId, DICT_ID).eq(SysDictItem::getItemValue, String.valueOf(clientId));
+    SysDictItem dictItem = sysDictItemService.getOne(wrapper);
+    if (dictItem != null) {
+      dictItem.setItemText(clientName);
+      sysDictItemService.updateById(dictItem);
+    } else {
+      syncDictItem(clientName, clientId);
+    }
+  }
+  
+  private void deleteDictItem(String clientName) {
+    LambdaQueryWrapper<SysDictItem> wrapper = new LambdaQueryWrapper<>();
+    wrapper.eq(SysDictItem::getDictId, DICT_ID).eq(SysDictItem::getItemText, clientName);
+    sysDictItemService.remove(wrapper);
   }
   
   /**
@@ -90,10 +158,18 @@
    */
   @AutoLog("ClientConfig-閫氳繃id鍒犻櫎")
   @DeleteMapping("/delete")
+  @Transactional(rollbackFor = Exception.class)
+  @CacheEvict(value = CacheConst.SYS_DICT_CACHE, allEntries = true)
   @Operation(summary = "鍒犻櫎瀹㈡埛瑙勫垯")
   public Result<?> delete(@RequestParam String id) {
+    Client client = clientService.getById(id);
+    if (client == null) {
+      return Result.error("璁板綍涓嶅瓨鍦�");
+    }
+    String clientName = client.getClientName();
     clientService.removeById(id);
     clientConfigService.remove(new LambdaQueryWrapper<ClientConfig>().eq(ClientConfig::getClientId, id));
+    deleteDictItem(clientName);
     return Result.ok();
   }
   
diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientController.java b/jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientController.java
new file mode 100644
index 0000000..fc207d4
--- /dev/null
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientController.java
@@ -0,0 +1,42 @@
+package com.tievd.jyz.controller;
+
+import com.tievd.cube.commons.base.CubeController;
+import com.tievd.cube.commons.base.Result;
+import com.tievd.jyz.entity.Client;
+import com.tievd.jyz.service.IClientService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * Client
+ *
+ * @author      cube
+ * @since       2023-08-18
+ * @version     V2.0.0
+ */
+@Slf4j
+@RestController
+@RequestMapping("/jyz/client")
+@Tag(name = "瀹㈡埛绫诲瀷鎺ュ彛")
+public class ClientController extends CubeController<Client, IClientService> {
+
+  @Autowired
+  private IClientService clientService;
+  
+  /**
+   * 鑾峰彇瀹㈡埛绫诲瀷鍒楄〃
+   */
+  @GetMapping("/listClientType")
+  @Operation(summary = "鑾峰彇瀹㈡埛绫诲瀷鍒楄〃")
+  public Result<List<Client>> listClientType() {
+    List<Client> list = clientService.list();
+    return Result.ok(list);
+  }
+}
diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/controller/DataTableController.java b/jyz-base-start/src/main/java/com/tievd/jyz/controller/DataTableController.java
index 2427ed2..7a40e36 100644
--- a/jyz-base-start/src/main/java/com/tievd/jyz/controller/DataTableController.java
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/controller/DataTableController.java
@@ -66,6 +66,15 @@
         StatDataTableVo total = oilRecordService.statisTotal(param);
         return Result.ok(total);
     }
+
+    @PostMapping("/statisOilFreqCompare")
+    @Operation(summary = "娲诲姩鍓嶅悗杞﹁締鍔犳补棰戞缁熻")
+    public Result<?> statisOilFreqCompare(@RequestBody DataStatisReqVo param) {
+        LoginUser user = SystemContextUtil.currentLoginUser();
+        param.setOrgCodeIfnull(user.getOrgCode());
+        List<Map> list = oilRecordService.statisOilFreqCompare(param);
+        return Result.ok(list);
+    }
     
     @GetMapping("/clientTop")
     @Operation(summary = "瀹㈡埛绫诲瀷top10")
@@ -118,6 +127,8 @@
     @PostMapping("/statTrend")
     @Operation(summary = "鍔犳补绔欑粺璁�-椤堕儴鏉″舰鍥�")
     public Result<?> statTrend(@RequestBody DataStatisReqVo param) {
+        LoginUser user = SystemContextUtil.currentLoginUser();
+        param.setOrgCodeIfnull(user.getOrgCode());
         JSONObject statFan;
         if (param.getTrendType() == DataStatisReqVo.TrendType.CLIENT || param.getTrendType() == DataStatisReqVo.TrendType.LOSE_CLIENT) {
             statFan = oilRecordService.statTrendClient(param);
@@ -126,6 +137,15 @@
         }
         return Result.ok(statFan);
     }
+
+    @PostMapping("/statTrendDetail")
+    @Operation(summary = "鍔犳补绔欑粺璁�-瓒嬪娍鍒嗘瀽鏄庣粏")
+    public Result<?> statTrendDetail(@RequestBody DataStatisReqVo param) {
+        LoginUser user = SystemContextUtil.currentLoginUser();
+        param.setOrgCodeIfnull(user.getOrgCode());
+        List<Map<String, Object>> list = oilRecordService.statTrendDetail(param);
+        return Result.ok(list);
+    }
     
     
 }
diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/entity/Client.java b/jyz-base-start/src/main/java/com/tievd/jyz/entity/Client.java
index ab4c58e..3e4484a 100644
--- a/jyz-base-start/src/main/java/com/tievd/jyz/entity/Client.java
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/entity/Client.java
@@ -37,6 +37,9 @@
     @TableField("create_time")
     private Timestamp createTime;
 
+    @TableField("history_oil_count")
+    private Integer historyOilCount;
+
     @Override
     public Serializable pkVal() {
         return this.id;
diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/entity/ClientConfig.java b/jyz-base-start/src/main/java/com/tievd/jyz/entity/ClientConfig.java
index 05a5c72..1aa5cab 100644
--- a/jyz-base-start/src/main/java/com/tievd/jyz/entity/ClientConfig.java
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/entity/ClientConfig.java
@@ -61,6 +61,22 @@
     @TableField("count_num")
     private Integer countNum;
 
+    @Schema(description = "鍔犳补瓒嬪娍: 0-鏃� 1-绋冲畾 2-鍑忓皯")
+    @TableField("count_trend")
+    private Byte countTrend;
+
+    @Schema(description = "瑙勫垯绫诲瀷: 1-鍔犳补棰戞 2-鍔犳补瓒嬪娍")
+    @TableField("rule_type")
+    private Byte ruleType;
+
+    @Schema(description = "鍘嗗彶鏈堟暟")
+    @TableField("history_months")
+    private Integer historyMonths;
+
+    @Schema(description = "杩戞湡鏈堟暟")
+    @TableField("recent_months")
+    private Integer recentMonths;
+
     @Override
     public Serializable pkVal() {
         return this.id;
diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/entity/vo/DataStatisReqVo.java b/jyz-base-start/src/main/java/com/tievd/jyz/entity/vo/DataStatisReqVo.java
index 3e63897..edb793a 100644
--- a/jyz-base-start/src/main/java/com/tievd/jyz/entity/vo/DataStatisReqVo.java
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/entity/vo/DataStatisReqVo.java
@@ -28,6 +28,18 @@
 
     @Schema(description = "缁撴潫鏃堕棿")
     private String endTime;
+
+    @Schema(description = "娲诲姩鍓嶅紑濮嬫椂闂�")
+    private String beforeStartTime;
+
+    @Schema(description = "娲诲姩鍓嶇粨鏉熸椂闂�")
+    private String beforeEndTime;
+
+    @Schema(description = "娲诲姩鍚庡紑濮嬫椂闂�")
+    private String afterStartTime;
+
+    @Schema(description = "娲诲姩鍚庣粨鏉熸椂闂�")
+    private String afterEndTime;
     
     public void setOrgCodeIfnull(String orgCode) {
         if (this.orgCode == null || this.orgCode.equals("")){
@@ -46,6 +58,12 @@
     
     @Schema(description = "HOURS, DAYS, MONTHS")
     private StatUnit timeUnit = StatUnit.HOURS;
+
+    @Schema(description = "瓒嬪娍鍥剧偣浣嶆椂闂�")
+    private String statTime;
+
+    @Schema(description = "瓒嬪娍鍥剧郴鍒楀悕绉�")
+    private String seriesName;
     
     private DataStatisReqVo setTimeUnit(String timeUnit){
         this.timeUnit = StatUnit.valueOf(timeUnit);
diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/mapper/OilRecordMapper.java b/jyz-base-start/src/main/java/com/tievd/jyz/mapper/OilRecordMapper.java
index c478180..dabd2a9 100644
--- a/jyz-base-start/src/main/java/com/tievd/jyz/mapper/OilRecordMapper.java
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/mapper/OilRecordMapper.java
@@ -100,6 +100,8 @@
     List<Map> statisOrgTopOil(DataStatisReqVo param);
     
     List<Map> statisOrgTopVolume(DataStatisReqVo param);
+
+    List<Map> statisOilFreqCompare(DataStatisReqVo param);
     
     List<StatDataTableVo> statFanByModel(DataStatisReqVo param);
     
diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/service/IOilRecordService.java b/jyz-base-start/src/main/java/com/tievd/jyz/service/IOilRecordService.java
index df76d7c..f7ee057 100644
--- a/jyz-base-start/src/main/java/com/tievd/jyz/service/IOilRecordService.java
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/service/IOilRecordService.java
@@ -40,6 +40,8 @@
     List<Map> statisOrgTopOil(DataStatisReqVo param);
     
     List<Map> statisOrgTopVolume(DataStatisReqVo param);
+
+    List<Map> statisOilFreqCompare(DataStatisReqVo param);
     
     JSONObject statFan(DataStatisReqVo param);
     
@@ -48,4 +50,6 @@
     JSONObject statTrend(DataStatisReqVo param);
     
     JSONObject statTrendClient(DataStatisReqVo param);
+
+    List<Map<String, Object>> statTrendDetail(DataStatisReqVo param);
 }
diff --git a/jyz-base-start/src/main/java/com/tievd/jyz/service/impl/OilRecordServiceImpl.java b/jyz-base-start/src/main/java/com/tievd/jyz/service/impl/OilRecordServiceImpl.java
index d9dbd53..1e01e1d 100644
--- a/jyz-base-start/src/main/java/com/tievd/jyz/service/impl/OilRecordServiceImpl.java
+++ b/jyz-base-start/src/main/java/com/tievd/jyz/service/impl/OilRecordServiceImpl.java
@@ -154,6 +154,11 @@
     public List<Map> statisOrgTopVolume(DataStatisReqVo param) {
         return oilRecordMapper.statisOrgTopVolume(param);
     }
+
+    @Override
+    public List<Map> statisOilFreqCompare(DataStatisReqVo param) {
+        return oilRecordMapper.statisOilFreqCompare(param);
+    }
     
     @Override
     public JSONObject statFan(DataStatisReqVo param) {
@@ -363,6 +368,131 @@
         res.put("lineData", lineDatas);
         return res;
     }
+
+    @Override
+    public List<Map<String, Object>> statTrendDetail(DataStatisReqVo param) {
+        if (param.getTrendType() == null || param.getTimeUnit() == null || param.getStatTime() == null) {
+            return new ArrayList<>();
+        }
+        DataStatisReqVo.TrendType trendType = param.getTrendType();
+        DataStatisReqVo.StatUnit timeUnit = param.getTimeUnit();
+        LocalDateTime[] timeRange = getTrendTimeRange(timeUnit);
+        LocalDateTime timeLimit = timeRange[0];
+        LocalDateTime timeLimitRight = timeRange[1];
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(timeUnit.statFormat());
+        String statTime = param.getStatTime();
+        List<Map<String, Object>> detailList = new ArrayList<>();
+
+        if (trendType == DataStatisReqVo.TrendType.TRAFFIC) {
+            LambdaQueryWrapper<TrafficFlow> wrapper = new LambdaQueryWrapper<TrafficFlow>()
+                    .ge(TrafficFlow::getCaptureTime, timeLimit.toString())
+                    .le(TrafficFlow::getCaptureTime, timeLimitRight.toString())
+                    .likeRight(TrafficFlow::getOrgCode, param.getOrgCode())
+                    .orderByDesc(TrafficFlow::getCaptureTime);
+            List<TrafficFlow> list = trafficFlowMapper.selectList(wrapper);
+            for (TrafficFlow trafficFlow : list) {
+                if (!matchStatTime(trafficFlow.getCaptureTime().toLocalDateTime(), formatter, statTime)) {
+                    continue;
+                }
+                Map<String, Object> row = new LinkedHashMap<>();
+                row.put("id", trafficFlow.getId());
+                row.put("captureTime", trafficFlow.getCaptureTime());
+                row.put("carCount", trafficFlow.getCarCount());
+                row.put("modelCode", trafficFlow.getModelCode());
+                row.put("cameraCode", trafficFlow.getCameraCode());
+                detailList.add(row);
+            }
+            return detailList;
+        }
+
+        if (trendType == DataStatisReqVo.TrendType.CLIENT || trendType == DataStatisReqVo.TrendType.LOSE_CLIENT) {
+            LambdaQueryWrapper<OilStatis> wrapper = new LambdaQueryWrapper<OilStatis>()
+                    .ge(OilStatis::getUpdateTimeSelf, timeLimit.toString())
+                    .le(OilStatis::getUpdateTimeSelf, timeLimitRight.toString())
+                    .likeRight(OilStatis::getOrgCode, param.getOrgCode())
+                    .orderByDesc(OilStatis::getUpdateTimeSelf);
+            List<OilStatis> list = oilStaticMapper.selectList(wrapper);
+            for (OilStatis oilStatis : list) {
+                if (!matchStatTime(oilStatis.getUpdateTimeSelf().toLocalDateTime(), formatter, statTime)) {
+                    continue;
+                }
+                if (trendType == DataStatisReqVo.TrendType.CLIENT
+                        && param.getSeriesName() != null
+                        && !param.getSeriesName().equals(oilStatis.getClientName())) {
+                    continue;
+                }
+                if (trendType == DataStatisReqVo.TrendType.LOSE_CLIENT
+                        && (oilStatis.getClientId() == null || oilStatis.getClientId() != SystemConstant.LOSE_CLIENT_ID)) {
+                    continue;
+                }
+                Map<String, Object> row = new LinkedHashMap<>();
+                row.put("id", oilStatis.getId());
+                row.put("updateTimeSelf", oilStatis.getUpdateTimeSelf());
+                row.put("licenseNum", oilStatis.getLicenseNum());
+                row.put("clientName", oilStatis.getClientName());
+                row.put("oilCount", oilStatis.getOilCount());
+                row.put("oilSum", oilStatis.getOilSum());
+                detailList.add(row);
+            }
+            return detailList;
+        }
+
+        LambdaQueryWrapper<OilRecord> wrapper = new LambdaQueryWrapper<OilRecord>()
+                .ge(OilRecord::getStartTime, timeLimit.toString())
+                .le(OilRecord::getStartTime, timeLimitRight.toString())
+                .likeRight(OilRecord::getOrgCode, param.getOrgCode())
+                .orderByDesc(OilRecord::getStartTime);
+        List<OilRecord> records = this.list(wrapper);
+        for (OilRecord oilRecord : records) {
+            if (!matchStatTime(oilRecord.getStartTime().toLocalDateTime(), formatter, statTime)) {
+                continue;
+            }
+            if (trendType == DataStatisReqVo.TrendType.OIL
+                    && (oilRecord.getBehavior() == null || oilRecord.getBehavior().intValue() != SystemConstant.BEHAVIOR_TYPE_OIL)) {
+                continue;
+            }
+            if (trendType == DataStatisReqVo.TrendType.OIL_vOLUME
+                    && (oilRecord.getBehavior() == null || oilRecord.getBehavior().intValue() != SystemConstant.BEHAVIOR_TYPE_OIL)) {
+                continue;
+            }
+            Map<String, Object> row = new LinkedHashMap<>();
+            row.put("id", oilRecord.getId());
+            row.put("startTime", oilRecord.getStartTime());
+            row.put("licenseNum", oilRecord.getLicenseNum());
+            row.put("behavior", oilRecord.getBehavior());
+            row.put("behaviorText", behaviorText(oilRecord.getBehavior()));
+            row.put("oilPosition", oilRecord.getOilPosition());
+            row.put("oilVolume", oilRecord.getOilVolume());
+            row.put("spandTime", oilRecord.getSpandTime());
+            detailList.add(row);
+        }
+        return detailList;
+    }
+
+    private LocalDateTime[] getTrendTimeRange(DataStatisReqVo.StatUnit timeUnit) {
+        LocalDateTime timeLimit = LocalDateTime.now()
+                .minus(timeUnit.value(), ChronoUnit.valueOf(timeUnit.name()))
+                .with(timeUnit.initField(), 1);
+        LocalDateTime timeLimitRight = LocalDateTime.now().with(timeUnit.initField(), 1);
+        return new LocalDateTime[]{timeLimit, timeLimitRight};
+    }
+
+    private boolean matchStatTime(LocalDateTime time, DateTimeFormatter formatter, String statTime) {
+        return formatter.format(time).equals(statTime);
+    }
+
+    private String behaviorText(Byte behavior) {
+        if (behavior == null) {
+            return "";
+        }
+        if (behavior.intValue() == SystemConstant.BEHAVIOR_TYPE_OIL) {
+            return "鍔犳补";
+        }
+        if (behavior.intValue() == SystemConstant.BEHAVIOR_TYPE_TMP) {
+            return "鍋滈潬";
+        }
+        return behavior.toString();
+    }
     
     private <E> JSONObject  dataTransLists(
             List<E> dataList,
diff --git a/jyz-base-start/src/main/resources/xml/OilRecordMapper.xml b/jyz-base-start/src/main/resources/xml/OilRecordMapper.xml
index a03f95e..1c5b368 100644
--- a/jyz-base-start/src/main/resources/xml/OilRecordMapper.xml
+++ b/jyz-base-start/src/main/resources/xml/OilRecordMapper.xml
@@ -90,6 +90,22 @@
             <if test="orgCode != null and orgCode != ''">and org_code like concat(#{orgCode}, '%')</if>
         </where>
     </sql>
+    <sql id="statBeforeOilFreqCondition">
+        <where>
+            and behavior = 1
+            <if test="beforeStartTime != null and beforeStartTime != ''">and start_time >= #{beforeStartTime}</if>
+            <if test="beforeEndTime != null and beforeEndTime != ''">and start_time &lt; #{beforeEndTime}</if>
+            <if test="orgCode != null and orgCode != ''">and org_code like concat(#{orgCode}, '%')</if>
+        </where>
+    </sql>
+    <sql id="statAfterOilFreqCondition">
+        <where>
+            and behavior = 1
+            <if test="afterStartTime != null and afterStartTime != ''">and start_time >= #{afterStartTime}</if>
+            <if test="afterEndTime != null and afterEndTime != ''">and start_time &lt; #{afterEndTime}</if>
+            <if test="orgCode != null and orgCode != ''">and org_code like concat(#{orgCode}, '%')</if>
+        </where>
+    </sql>
     <select id="statisTotal" parameterType="com.tievd.jyz.entity.vo.DataStatisReqVo" resultType="com.tievd.jyz.entity.vo.StatDataTableVo">
         select
         *,
@@ -183,6 +199,38 @@
         GROUP BY org_code
         limit 10
     </select>
+    <select id="statisOilFreqCompare" resultType="java.util.Map" parameterType="com.tievd.jyz.entity.vo.DataStatisReqVo">
+        select
+        l.licenseNum licenseNum,
+        ifnull(b.beforeOilCount, 0) beforeOilCount,
+        ifnull(a.afterOilCount, 0) afterOilCount,
+        ifnull(a.afterOilCount, 0) - ifnull(b.beforeOilCount, 0) diffOilCount,
+        case
+            when ifnull(b.beforeOilCount, 0) = 0 then null
+            else round((ifnull(a.afterOilCount, 0) - ifnull(b.beforeOilCount, 0)) * 100 / ifnull(b.beforeOilCount, 0), 2)
+        end diffRate
+        from (
+            select license_num licenseNum from t_oil_record
+            <include refid="statBeforeOilFreqCondition"/>
+            union
+            select license_num licenseNum from t_oil_record
+            <include refid="statAfterOilFreqCondition"/>
+        ) l
+        left join (
+            select license_num licenseNum, count(1) beforeOilCount
+            from t_oil_record
+            <include refid="statBeforeOilFreqCondition"/>
+            group by license_num
+        ) b on l.licenseNum = b.licenseNum
+        left join (
+            select license_num licenseNum, count(1) afterOilCount
+            from t_oil_record
+            <include refid="statAfterOilFreqCondition"/>
+            group by license_num
+        ) a on l.licenseNum = a.licenseNum
+        order by afterOilCount desc, beforeOilCount desc, licenseNum asc
+        limit 200
+    </select>
     <select id="statFanByModel" resultType="com.tievd.jyz.entity.vo.StatDataTableVo" parameterType="com.tievd.jyz.entity.vo.DataStatisReqVo">
         select
         count(if(behavior=1,1,null)) oilCount,

--
Gitblit v1.8.0