74af7e7e3ee39e25f73525391b13face373e350e..963a8c24874c2e10a329a6ea39774bc5eda0f762
2026-03-25 zxl
销售金额
963a8c 对比 | 目录
2026-03-25 zxl
销售金额
74e332 对比 | 目录
2026-03-25 zxl
销售金额
881976 对比 | 目录
2026-03-25 zxl
Merge remote-tracking branch 'origin/show-demo' into show_demo
0b39ed 对比 | 目录
2026-03-25 peng
调整
2e5c2b 对比 | 目录
2026-03-25 zxl
3.25标签功能
d1dfb6 对比 | 目录
2026-03-24 peng
调整
73d124 对比 | 目录
2026-03-24 peng
调整
ca41db 对比 | 目录
14个文件已修改
7个文件已添加
1262 ■■■■■ 已修改文件
jyz-base-start/src/main/java/com/tievd/jyz/Timer/SystemSchedule.java 130 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/controller/ActivityController.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientConfigController.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientController.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/controller/DataTableController.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/controller/DepartLabelController.java 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/controller/OilRecordController.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/entity/Client.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/entity/ClientConfig.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/entity/DepartLabel.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/entity/OilRecord.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/entity/vo/DataStatisReqVo.java 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/entity/vo/StatDataTableVo.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/mapper/DepartLabelMapper.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/mapper/OilRecordMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/service/IDepartLabelService.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/service/IOilRecordService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/service/impl/DepartLabelServiceImpl.java 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/java/com/tievd/jyz/service/impl/OilRecordServiceImpl.java 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/resources/xml/DepartLabelMapper.xml 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jyz-base-start/src/main/resources/xml/OilRecordMapper.xml 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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;
        }
    }
    
}
jyz-base-start/src/main/java/com/tievd/jyz/controller/ActivityController.java
@@ -47,6 +47,9 @@
  @Autowired
  IActOrgRefService actOrgRefService;
  
  @Autowired
  private com.tievd.jyz.mapper.OilRecordMapper oilRecordMapper;
  /**
   * 分页列表查询
   */
@@ -156,6 +159,41 @@
    Activity activity = activityService.getById(id);
    return Result.ok(activity);
  }
  /**
   * 查看车辆加油频次
   */
  @GetMapping("/getVehicleFrequency")
  @Operation(description = "查看车辆加油频次")
  public Result<?> getVehicleFrequency(@RequestParam Integer actId) {
    Activity activity = activityService.getById(actId);
    if (activity == null) {
      return Result.error("活动不存在");
    }
    List<ActOrgRef> orgRefs = actOrgRefService.list(new LambdaQueryWrapper<ActOrgRef>().eq(ActOrgRef::getActId, actId));
    if (orgRefs == null || orgRefs.isEmpty()) {
      return Result.error("活动未关联机构");
    }
    List<String> orgCodes = new ArrayList<>();
    for (ActOrgRef ref : orgRefs) {
      orgCodes.add(ref.getOrgCode());
    }
    java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String startTimeStr = sdf.format(activity.getStartTime());
    String endTimeStr = sdf.format(activity.getEndTime());
    java.util.Map<String, Object> result = new java.util.HashMap<>();
    result.put("activity", activity);
    result.put("beforeActivity", oilRecordMapper.getVehicleFrequencyBeforeActivity(startTimeStr, orgCodes));
    result.put("duringActivity", oilRecordMapper.getVehicleFrequencyDuringActivity(startTimeStr, endTimeStr, orgCodes));
    result.put("afterActivity", oilRecordMapper.getVehicleFrequencyAfterActivity(endTimeStr, orgCodes));
    return Result.ok(result);
  }
  /**
   * 导出excel
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();
  }
  
jyz-base-start/src/main/java/com/tievd/jyz/controller/ClientController.java
New file
@@ -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);
  }
}
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")
@@ -106,6 +115,15 @@
        return Result.ok(res);
    }
    
    @PostMapping("/statBar")
    @Operation(summary = "加油站统计-柱状图")
    public Result<?> statBar(@RequestBody DataStatisReqVo param) {
        LoginUser user = SystemContextUtil.currentLoginUser();
        param.setOrgCodeIfnull(user.getOrgCode());
        JSONObject statBar = oilRecordService.statBar(param);
        return Result.ok(statBar);
    }
    @PostMapping("/statFan")
    @Operation(summary = "加油站统计-中部报表(扇形图)")
    public Result<?> statFan(@RequestBody DataStatisReqVo param) {
@@ -118,6 +136,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 +146,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);
    }
    
    
}
jyz-base-start/src/main/java/com/tievd/jyz/controller/DepartLabelController.java
New file
@@ -0,0 +1,128 @@
package com.tievd.jyz.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tievd.cube.commons.annotations.AutoLog;
import com.tievd.cube.commons.base.CubeController;
import com.tievd.cube.commons.base.Result;
import com.tievd.jyz.entity.DepartLabel;
import com.tievd.jyz.service.IDepartLabelService;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/jyz/departLabel")
public class DepartLabelController extends CubeController<DepartLabel, IDepartLabelService> {
    @Autowired
    private IDepartLabelService departLabelService;
    @GetMapping("/list")
    @Operation(summary = "分页查询机构标签")
    public Result<?> queryPageList(@RequestParam(required = false) String labelName,
                                    @RequestParam(required = false) String parentCode,
                                    @RequestParam(required = false) String parentId,
                                    @RequestParam(defaultValue = "1") Integer pageNo,
                                    @RequestParam(defaultValue = "10") Integer pageSize) {
        List<Map<String, Object>> list = departLabelService.queryDepartLabelList(labelName, parentCode, parentId);
        int total = list.size();
        int start = (pageNo - 1) * pageSize;
        int end = Math.min(start + pageSize, total);
        Page<Map<String, Object>> page = new Page<>(pageNo, pageSize, total);
        if (start < total) {
            page.setRecords(list.subList(start, end));
        } else {
            page.setRecords(Collections.emptyList());
        }
        return Result.ok(page);
    }
    @GetMapping("/listLabels")
    @Operation(summary = "获取所有标签名称")
    public Result<?> listLabels(@RequestParam(required = false) String parentCode,
                                  @RequestParam(required = false) String parentId) {
        List<String> labels = departLabelService.queryAllLabelNames(parentCode, parentId);
        return Result.ok(labels);
    }
    @AutoLog("机构标签-添加")
    @PostMapping("/add")
    @Operation(summary = "添加机构标签")
    public Result<?> add(@RequestBody DepartLabel departLabel) {
        LambdaQueryWrapper<DepartLabel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DepartLabel::getDepartId, departLabel.getDepartId());
        queryWrapper.eq(DepartLabel::getLabelName, departLabel.getLabelName());
        if (departLabelService.count(queryWrapper) > 0) {
            return Result.error("该机构已存在此标签");
        }
        departLabelService.save(departLabel);
        return Result.ok();
    }
    @AutoLog("机构标签-删除")
    @DeleteMapping("/delete")
    @Operation(summary = "删除机构标签")
    public Result<?> delete(@RequestBody Map<String, String> params) {
        String departId = params.get("departId");
        String labelName = params.get("labelName");
        LambdaQueryWrapper<DepartLabel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DepartLabel::getDepartId, departId);
        if (labelName != null && !labelName.isEmpty()) {
            queryWrapper.eq(DepartLabel::getLabelName, labelName);
        }
        departLabelService.remove(queryWrapper);
        return Result.ok();
    }
    @AutoLog("机构标签-更新")
    @PutMapping("/update")
    @Operation(summary = "更新机构标签")
    public Result<?> update(@RequestBody Map<String, String> params) {
        String departId = params.get("departId");
        String labelName = params.get("labelName");
        LambdaQueryWrapper<DepartLabel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DepartLabel::getDepartId, departId);
        List<DepartLabel> labels = departLabelService.list(queryWrapper);
        if (labels.isEmpty()) {
            return Result.ok();
        }
        departLabelService.remove(queryWrapper);
        if (labelName != null && !labelName.isEmpty()) {
            String[] labelArray = labelName.split(",");
            for (String label : labelArray) {
                if (!label.trim().isEmpty()) {
                    DepartLabel departLabel = new DepartLabel();
                    departLabel.setDepartId(departId);
                    departLabel.setLabelName(label.trim());
                    departLabelService.save(departLabel);
                }
            }
        }
        return Result.ok();
    }
    @PostMapping("/queryOrgOilCount")
    @Operation(summary = "查询站点加油数")
    public Result<?> queryOrgOilCount(@RequestBody Map<String, String> params) {
        String orgCode = params.get("orgCode");
        String startTime = params.get("startTime");
        String endTime = params.get("endTime");
        List<Map<String, Object>> oilCountList = departLabelService.queryOrgOilCount(orgCode, startTime, endTime);
        return Result.ok(oilCountList);
    }
}
jyz-base-start/src/main/java/com/tievd/jyz/controller/OilRecordController.java
@@ -114,18 +114,17 @@
    
    for(OilRecord tmpOilRecord:pageList.getRecords()){
      try{
        if(StringUtils.isNotEmpty(tmpOilRecord.getImgPath())){
          String randomImagePath = getRandomImagePath();
          if(randomImagePath != null){
            tmpOilRecord.setImgPath(randomImagePath);
          }
        }
        if(StringUtils.isNotEmpty(tmpOilRecord.getOutImgPath())){
          String randomImagePath = getRandomImagePath();
          if(randomImagePath != null){
            tmpOilRecord.setOutImgPath(randomImagePath);
          String randomImagePath2 = getRandomImagePath();
          if(randomImagePath2 != null){
            tmpOilRecord.setOutImgPath(randomImagePath2);
          }
        }
      }catch (Exception ex){
        log.error("生成图片路径失败",ex);
      }
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;
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;
jyz-base-start/src/main/java/com/tievd/jyz/entity/DepartLabel.java
New file
@@ -0,0 +1,44 @@
package com.tievd.jyz.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
@Data
@Accessors(chain = true)
@TableName("t_depart_label")
@Schema(name = "DepartLabel", description = "机构标签关联表")
public class DepartLabel extends Model<DepartLabel> {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @Schema(description = "机构ID")
    @TableField("depart_id")
    private String departId;
    @Schema(description = "标签名称")
    @TableField("label_name")
    private String labelName;
    @TableField("create_time")
    private Date createTime;
    @TableField("update_time")
    private Date updateTime;
    @Override
    public Serializable pkVal() {
        return this.id;
    }
}
jyz-base-start/src/main/java/com/tievd/jyz/entity/OilRecord.java
@@ -101,6 +101,14 @@
    @TableField("record_day")
    private String recordDay;
    
    @Schema(description = "油品类型:92,95,98,柴油")
    @TableField("oil_type")
    private String oilType;
    @Schema(description = "总金额")
    @TableField("total_amount")
    private java.math.BigDecimal totalAmount;
    @Schema(description = "创建时间")
    @TableField("create_time")
    private Date createTime;
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);
@@ -90,12 +108,20 @@
    }
    
    public enum TrendType {
        TRAFFIC(1, StatDataTableVo::getCarCount, StatDataTableVo::getEntryRate, "车流量", "拐入率"),
        OIL(2, StatDataTableVo::getOilCount, StatDataTableVo::getOilVolume, "加油数", "油品销量"),
        OIL_vOLUME(3, StatDataTableVo::getOilVolume, t -> 100 * (t.getOilVolume() - t.getPreStatVo().getOilVolume()) / (t.getPreStatVo().getOilVolume() + 1), "油品销量", "环比"),
        SPAND_AVG(4, StatDataTableVo::getSpandAvg, t -> 100 * (t.getSpandAvg() - t.getPreStatVo().getSpandAvg()) / (t.getPreStatVo().getSpandAvg() + 1), "通过率", "环比"),
        CLIENT(5, null),
        LOSE_CLIENT(6, null);
        TRAFFIC(0, StatDataTableVo::getCarCount, StatDataTableVo::getEntryRate, "车流量", "拐入率"),
        OIL(1, StatDataTableVo::getOilCount, StatDataTableVo::getOilVolume, "加油数", "油品销量"),
        OIL_vOLUME(2, StatDataTableVo::getOilVolume, t -> 100 * (t.getOilVolume() - t.getPreStatVo().getOilVolume()) / (t.getPreStatVo().getOilVolume() + 1), "油品销量", "环比"),
        SPAND_AVG(3, StatDataTableVo::getSpandAvg, t -> 100 * (t.getSpandAvg() - t.getPreStatVo().getSpandAvg()) / (t.getPreStatVo().getSpandAvg() + 1), "通过率", "环比"),
        CLIENT(4, null),
        LOSE_CLIENT(5, null),
        SALES_AMOUNT(6, StatDataTableVo::getTotalAmount, t -> {
            java.math.BigDecimal current = t.getTotalAmount();
            java.math.BigDecimal previous = t.getPreStatVo().getTotalAmount();
            if (previous.compareTo(java.math.BigDecimal.ZERO) == 0) {
                return java.math.BigDecimal.ZERO;
            }
            return current.subtract(previous).multiply(new java.math.BigDecimal(100)).divide(previous, 2, java.math.RoundingMode.HALF_UP);
        }, "销售金额", "环比");
        
        int val;
        
jyz-base-start/src/main/java/com/tievd/jyz/entity/vo/StatDataTableVo.java
@@ -41,6 +41,9 @@
    @Schema(description = "回头率")
    private String rebackRate;
    
    @Schema(description = "销售金额")
    private java.math.BigDecimal totalAmount;
    
    
    @Schema(description = "加油位")
@@ -48,6 +51,9 @@
    
    @Schema(description = "车型")
    private String modelName;
    @Schema(description = "油品类型")
    private String oilType;
    
    @Schema(description = "时间轴")
    private LocalDateTime statTime;
@@ -72,6 +78,22 @@
        this.sumSpand += sumSpand;
    }
    
    public void addTotalAmount(java.math.BigDecimal totalAmount) {
        if (this.totalAmount == null) {
            this.totalAmount = java.math.BigDecimal.ZERO;
        }
        if (totalAmount != null) {
            this.totalAmount = this.totalAmount.add(totalAmount);
        }
    }
    public java.math.BigDecimal getTotalAmount() {
        if (totalAmount == null) {
            totalAmount = java.math.BigDecimal.ZERO;
        }
        return totalAmount;
    }
    public int getSpandAvg() {
        if (spandAvg == null) {
            spandAvg = appearCount == 0 ? 0 : sumSpand / appearCount;
jyz-base-start/src/main/java/com/tievd/jyz/mapper/DepartLabelMapper.java
New file
@@ -0,0 +1,21 @@
package com.tievd.jyz.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tievd.jyz.entity.DepartLabel;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface DepartLabelMapper extends BaseMapper<DepartLabel> {
    List<Map<String, Object>> queryDepartLabelList(@Param("labelName") String labelName,
                                                     @Param("parentCode") String parentCode,
                                                     @Param("parentId") String parentId);
    List<String> queryAllLabelNames(@Param("parentCode") String parentCode, @Param("parentId") String parentId);
    List<Map<String, Object>> queryOrgOilCount(@Param("orgCode") String orgCode,
                                             @Param("startTime") String startTime,
                                             @Param("endTime") String endTime);
}
jyz-base-start/src/main/java/com/tievd/jyz/mapper/OilRecordMapper.java
@@ -100,10 +100,20 @@
    List<Map> statisOrgTopOil(DataStatisReqVo param);
    
    List<Map> statisOrgTopVolume(DataStatisReqVo param);
    List<Map> statisOilFreqCompare(DataStatisReqVo param);
    
    List<StatDataTableVo> statFanByModel(DataStatisReqVo param);
    
    List<StatDataTableVo> statFanByPosition(DataStatisReqVo param);
    
    List<StatDataTableVo> statFanByOilType(DataStatisReqVo param);
    List<StatDataTableVo> statBarByModel(DataStatisReqVo param);
    Map getVehicleFrequencyBeforeActivity(@Param("startTime") String startTime, @Param("orgCodes") List<String> orgCodes);
    Map getVehicleFrequencyDuringActivity(@Param("startTime") String startTime, @Param("endTime") String endTime, @Param("orgCodes") List<String> orgCodes);
    Map getVehicleFrequencyAfterActivity(@Param("endTime") String endTime, @Param("orgCodes") List<String> orgCodes);
}
jyz-base-start/src/main/java/com/tievd/jyz/service/IDepartLabelService.java
New file
@@ -0,0 +1,18 @@
package com.tievd.jyz.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.tievd.jyz.entity.DepartLabel;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import java.util.Map;
public interface IDepartLabelService extends IService<DepartLabel> {
    List<Map<String, Object>> queryDepartLabelList(String labelName, String parentCode, String parentId);
    List<String> queryAllLabelNames(String parentCode,
                                    String parentId);
    List<Map<String, Object>> queryOrgOilCount(String orgCode, String startTime, String endTime);
}
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);
}
jyz-base-start/src/main/java/com/tievd/jyz/service/impl/DepartLabelServiceImpl.java
New file
@@ -0,0 +1,200 @@
package com.tievd.jyz.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tievd.jyz.entity.DepartLabel;
import com.tievd.jyz.mapper.DepartLabelMapper;
import com.tievd.jyz.service.IDepartLabelService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class DepartLabelServiceImpl extends ServiceImpl<DepartLabelMapper, DepartLabel> implements IDepartLabelService {
    @Override
    public List<Map<String, Object>> queryDepartLabelList(String labelName, String parentCode, String parentId) {
        return baseMapper.queryDepartLabelList(labelName, parentCode, parentId);
    }
    @Override
    public List<String> queryAllLabelNames(String parentCode, String parentId) {
        return baseMapper.queryAllLabelNames(parentCode, parentId);
    }
    @Override
    public List<Map<String, Object>> queryOrgOilCount(String orgCode, String startTime, String endTime) {
        List<Map<String, Object>> oilCountList = baseMapper.queryOrgOilCount(orgCode, startTime, endTime);
        System.out.println("=== queryOrgOilCount 开始 ===");
        System.out.println("orgCode: " + orgCode);
        System.out.println("startTime: " + startTime);
        System.out.println("endTime: " + endTime);
        System.out.println("oilCountList size: " + (oilCountList != null ? oilCountList.size() : 0));
        if (oilCountList == null || oilCountList.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, String> orgCodeToIdMap = new HashMap<>();
        Map<String, String> idToParentIdMap = new HashMap<>();
        Map<String, Integer> idOilCountMap = new HashMap<>();
        Map<String, Integer> idCarCountMap = new HashMap<>();
        Map<String, Integer> idStationCountMap = new HashMap<>();
        Map<String, Integer> idOilVolumeMap = new HashMap<>();
        for (Map<String, Object> item : oilCountList) {
            String orgCodeStr = (String) item.get("org_code");
            String departId = (String) item.get("depart_id");
            Object oilCountObj = item.get("oilCount");
            Integer oilCount = null;
            if (oilCountObj instanceof Integer) {
                oilCount = (Integer) oilCountObj;
            } else if (oilCountObj instanceof Number) {
                oilCount = ((Number) oilCountObj).intValue();
            } else if (oilCountObj instanceof String) {
                oilCount = Integer.parseInt((String) oilCountObj);
            }
            Object carCountObj = item.get("carCount");
            Integer carCount = null;
            if (carCountObj instanceof Integer) {
                carCount = (Integer) carCountObj;
            } else if (carCountObj instanceof Number) {
                carCount = ((Number) carCountObj).intValue();
            } else if (carCountObj instanceof String) {
                carCount = Integer.parseInt((String) carCountObj);
            }
            Object stationCountObj = item.get("stationCount");
            Integer stationCount = null;
            if (stationCountObj instanceof Integer) {
                stationCount = (Integer) stationCountObj;
            } else if (stationCountObj instanceof Number) {
                stationCount = ((Number) stationCountObj).intValue();
            } else if (stationCountObj instanceof String) {
                stationCount = Integer.parseInt((String) stationCountObj);
            }
            Object oilVolumeObj = item.get("oilVolume");
            Integer oilVolume = null;
            if (oilVolumeObj instanceof Integer) {
                oilVolume = (Integer) oilVolumeObj;
            } else if (oilVolumeObj instanceof Number) {
                oilVolume = ((Number) oilVolumeObj).intValue();
            } else if (oilVolumeObj instanceof String) {
                oilVolume = Integer.parseInt((String) oilVolumeObj);
            }
            if (departId != null) {
                orgCodeToIdMap.put(orgCodeStr, departId);
                if (oilCount != null) {
                    idOilCountMap.put(departId, oilCount);
                }
                if (carCount != null) {
                    idCarCountMap.put(departId, carCount);
                }
                if (stationCount != null) {
                    idStationCountMap.put(departId, stationCount);
                }
                if (oilVolume != null) {
                    idOilVolumeMap.put(departId, oilVolume);
                }
            }
        }
        List<Map<String, Object>> departList = baseMapper.queryDepartLabelList(null, orgCode, null);
        System.out.println("departList size: " + (departList != null ? departList.size() : 0));
        for (Map<String, Object> depart : departList) {
            String departId = (String) depart.get("id");
            Object parentIdObj = depart.get("parent_id");
            System.out.println("departId: " + departId + ", parentId: " + parentIdObj);
            if (parentIdObj != null) {
                String parentIdStr = parentIdObj.toString();
                if (parentIdStr != null && !parentIdStr.isEmpty()) {
                    String[] parentIds = parentIdStr.split(",");
                    for (String pid : parentIds) {
                        if (!pid.trim().isEmpty()) {
                            idToParentIdMap.put(departId, pid.trim());
                            System.out.println("  -> 父子关系: " + departId + " -> " + pid.trim());
                        }
                    }
                }
            }
        }
        System.out.println("idToParentIdMap size: " + idToParentIdMap.size());
        System.out.println("idOilCountMap: " + idOilCountMap);
        System.out.println("idCarCountMap: " + idCarCountMap);
        System.out.println("idStationCountMap: " + idStationCountMap);
        System.out.println("idOilVolumeMap: " + idOilVolumeMap);
        Map<String, Integer> finalOilCountMap = new HashMap<>(idOilCountMap);
        Map<String, Integer> finalCarCountMap = new HashMap<>(idCarCountMap);
        Map<String, Integer> finalStationCountMap = new HashMap<>(idStationCountMap);
        Map<String, Integer> finalOilVolumeMap = new HashMap<>(idOilVolumeMap);
        for (Map.Entry<String, String> entry : idToParentIdMap.entrySet()) {
            String childId = entry.getKey();
            String parentIdStr = entry.getValue();
            if (parentIdStr != null && !parentIdStr.isEmpty()) {
                Integer childOilCount = idOilCountMap.get(childId);
                if (childOilCount != null) {
                    finalOilCountMap.merge(parentIdStr, childOilCount, Integer::sum);
                    System.out.println("累加加油数: 父节点 " + parentIdStr + " += 子节点 " + childId + " 的 " + childOilCount);
                }
                Integer childCarCount = idCarCountMap.get(childId);
                if (childCarCount != null) {
                    finalCarCountMap.merge(parentIdStr, childCarCount, Integer::sum);
                    System.out.println("累加车流量: 父节点 " + parentIdStr + " += 子节点 " + childId + " 的 " + childCarCount);
                }
                Integer childStationCount = idStationCountMap.get(childId);
                if (childStationCount != null) {
                    finalStationCountMap.merge(parentIdStr, childStationCount, Integer::sum);
                    System.out.println("累加进站数: 父节点 " + parentIdStr + " += 子节点 " + childId + " 的 " + childStationCount);
                }
                Integer childOilVolume = idOilVolumeMap.get(childId);
                if (childOilVolume != null) {
                    finalOilVolumeMap.merge(parentIdStr, childOilVolume, Integer::sum);
                    System.out.println("累加油品销量: 父节点 " + parentIdStr + " += 子节点 " + childId + " 的 " + childOilVolume);
                }
            }
        }
        System.out.println("finalOilCountMap: " + finalOilCountMap);
        System.out.println("finalCarCountMap: " + finalCarCountMap);
        System.out.println("finalStationCountMap: " + finalStationCountMap);
        System.out.println("finalOilVolumeMap: " + finalOilVolumeMap);
        for (Map<String, Object> item : oilCountList) {
            String departId = (String) item.get("depart_id");
            Integer finalOilCount = finalOilCountMap.get(departId);
            if (finalOilCount != null) {
                item.put("oilCount", finalOilCount);
                System.out.println("更新 " + item.get("depart_name") + " 的加油数: " + finalOilCount);
            }
            Integer finalCarCount = finalCarCountMap.get(departId);
            if (finalCarCount != null) {
                item.put("carCount", finalCarCount);
                System.out.println("更新 " + item.get("depart_name") + " 的车流量: " + finalCarCount);
            }
            Integer finalStationCount = finalStationCountMap.get(departId);
            if (finalStationCount != null) {
                item.put("stationCount", finalStationCount);
                System.out.println("更新 " + item.get("depart_name") + " 的进站数: " + finalStationCount);
            }
            Integer finalOilVolume = finalOilVolumeMap.get(departId);
            if (finalOilVolume != null) {
                item.put("oilVolume", finalOilVolume);
                System.out.println("更新 " + item.get("depart_name") + " 的油品销量: " + finalOilVolume);
            }
        }
        System.out.println("=== queryOrgOilCount 结束 ===");
        return oilCountList;
    }
}
jyz-base-start/src/main/java/com/tievd/jyz/service/impl/OilRecordServiceImpl.java
@@ -154,13 +154,18 @@
    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) {
        JSONObject res;
        List<StatDataTableVo> dataList = new ArrayList<>();
        Function<StatDataTableVo, ?> xfunc = null;
        Function<StatDataTableVo, Integer> barfunc = null;
        Function<StatDataTableVo, ?> barfunc = null;
        switch(param.getType()) {
            case 1 :
                dataList = oilRecordMapper.statFanByModel(param);
@@ -182,6 +187,16 @@
                xfunc = StatDataTableVo::getOilPosition;
                barfunc = StatDataTableVo::getOilVolume;
                break;
            case 5 :
                dataList = oilRecordMapper.statFanByOilType(param);
                xfunc = StatDataTableVo::getOilType;
                barfunc = StatDataTableVo::getOilVolume;
                break;
            case 6 :
                dataList = oilRecordMapper.statFanByOilType(param);
                xfunc = StatDataTableVo::getOilType;
                barfunc = StatDataTableVo::getTotalAmount;
                break;
        }
        res = dataTransLists(dataList, xfunc, barfunc, null, "", "");
        return res;
@@ -193,8 +208,8 @@
        JSONObject res;
        List<StatDataTableVo> dataList;
        Function<StatDataTableVo, ?> xfunc;
        Function<StatDataTableVo, Integer> barfunc;
        Function<StatDataTableVo, Integer> linefunc;
        Function<StatDataTableVo, ?> barfunc;
        Function<StatDataTableVo, ?> linefunc;
        String barName = "";
        String lineName = "";
        if (param.getType() == 1) {
@@ -204,12 +219,26 @@
            linefunc = StatDataTableVo::getCarCount;
            barName = "加油数";
            lineName = "车流量";
        } else {
        } else if (param.getType() == 2) {
            dataList = oilRecordMapper.statFanByPosition(param);
            xfunc = StatDataTableVo::getOilPosition;
            barfunc = StatDataTableVo::getOilCount;
            linefunc = StatDataTableVo::getOilVolume;
            barName = "加油数";
            lineName = "油品销量";
        } else if (param.getType() == 3) {
            dataList = oilRecordMapper.statFanByOilType(param);
            xfunc = StatDataTableVo::getOilType;
            barfunc = StatDataTableVo::getOilVolume;
            linefunc = StatDataTableVo::getTotalAmount;
            barName = "油品销量";
            lineName = "销售金额";
        } else {
            dataList = oilRecordMapper.statFanByOilType(param);
            xfunc = StatDataTableVo::getOilType;
            barfunc = StatDataTableVo::getTotalAmount;
            linefunc = StatDataTableVo::getOilVolume;
            barName = "销售金额";
            lineName = "油品销量";
        }
        res = dataTransLists(dataList, xfunc, barfunc, linefunc, barName, lineName);
@@ -231,6 +260,7 @@
                .minus(timeUnit.value(), ChronoUnit.valueOf(timeUnit.name()))
                .with(timeUnit.initField(), 1);
        LocalDateTime timeLimitRight = LocalDateTime.now().with(timeUnit.initField(), 1);
        log.info("打印时间开始: {}, 打印时间结束: {}", timeLimit.toString(), timeLimitRight.toString());
        LambdaQueryWrapper wrapper = new LambdaQueryWrapper<OilRecord>()
                .ge(OilRecord::getStartTime, timeLimit.toString())
                .le(OilRecord::getStartTime, timeLimitRight.toString())
@@ -258,6 +288,7 @@
            statVo.addAppearCount(1);
            if (record.getBehavior().intValue() == SystemConstant.BEHAVIOR_TYPE_OIL) statVo.addOilCount(1);
            if (record.getBehavior().intValue() == SystemConstant.BEHAVIOR_TYPE_OIL) statVo.addOilVolume(record.getOilVolume());
            if (record.getBehavior().intValue() == SystemConstant.BEHAVIOR_TYPE_OIL) statVo.addTotalAmount(record.getTotalAmount());
            statVo.addSumSpand(record.getSpandTime());
        }
        
@@ -363,6 +394,136 @@
        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;
            }
            if (trendType == DataStatisReqVo.TrendType.SALES_AMOUNT
                    && (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("totalAmount", oilRecord.getTotalAmount());
            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,
@@ -372,16 +533,21 @@
            String barName,
            String lineName) {
        List xDatas = new ArrayList();
        List<Integer> barDatas = new ArrayList<>();
        List<Object> barDatas = new ArrayList<>();
        List lineDatas = new ArrayList<>();
        int sum = 0;
        double sum = 0;
        for (E statVo : dataList) {
            Object xData = "";
            int barData = 0;
            Object barData = 0;
            Object lineData = 0;
            try {
                xData = xDataMapper.apply(statVo);
                barData = Integer.valueOf(barDataMapper.apply(statVo).toString());
                Object barValue = barDataMapper.apply(statVo);
                if (barValue instanceof java.math.BigDecimal) {
                    barData = ((java.math.BigDecimal) barValue).doubleValue();
                } else {
                    barData = Integer.valueOf(barValue.toString());
                }
                if (lineDataMapper != null) lineData = lineDataMapper.apply(statVo);
            } catch (Exception e) {
                e.printStackTrace();
@@ -391,11 +557,18 @@
            xDatas.add(xData);
            barDatas.add(barData);
            lineDatas.add(lineData);
            sum += barData;
            if (barData instanceof Number) {
                sum += ((Number) barData).doubleValue();
            }
        }
        if (lineDataMapper == null) {
            int finalSum = sum;
            lineDatas = barDatas.stream().map(n -> n*100/ finalSum).collect(Collectors.toList());
            double finalSum = sum;
            lineDatas = barDatas.stream().map(n -> {
                if (n instanceof Number) {
                    return ((Number) n).doubleValue() * 100 / finalSum;
                }
                return 0;
            }).collect(Collectors.toList());
        }
        JSONObject res = new JSONObject();
        res.put("xData", xDatas);
jyz-base-start/src/main/resources/xml/DepartLabelMapper.xml
New file
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tievd.jyz.mapper.DepartLabelMapper">
    <select id="queryDepartLabelList" resultType="java.util.Map">
        SELECT
            s.id,
            s.id as depart_id,
            s.parent_id,
            COALESCE(GROUP_CONCAT(DISTINCT d.label_name SEPARATOR ','), '') as label_name,
            s.depart_name,
            s.org_code,
            s.create_time
        FROM sys_depart s
        LEFT JOIN t_depart_label d ON s.id = d.depart_id
        WHERE s.del_flag = 0
        <if test="parentCode != null and parentCode != ''">
            AND s.org_code LIKE CONCAT(#{parentCode}, '%')
        </if>
        <if test="parentId != null and parentId != ''">
            AND (s.id = #{parentId} OR FIND_IN_SET(#{parentId}, s.parent_id))
        </if>
        GROUP BY s.id, s.depart_name, s.org_code, s.create_time
        <if test="labelName != null and labelName != ''">
            HAVING FIND_IN_SET(#{labelName}, GROUP_CONCAT(DISTINCT d.label_name SEPARATOR ','))
        </if>
        ORDER BY s.id
    </select>
    <select id="queryAllLabelNames" resultType="java.lang.String">
        SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(label_name, ',', n.n), ',', -1) as label_name
        FROM t_label
        CROSS JOIN (
            SELECT 1 as n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
            SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL
            SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10
        ) n
        WHERE CHAR_LENGTH(label_name) - CHAR_LENGTH(REPLACE(label_name, ',', '')) >= n.n - 1
        AND label_type = '站点标签'
        ORDER BY label_name
    </select>
    <select id="queryOrgOilCount" resultType="java.util.Map">
        SELECT
            d.id as depart_id,
            d.org_code,
            d.depart_name,
            COALESCE(oil.oil_count, 0) as oilCount,
            COALESCE(traffic.car_count, 0) as carCount,
            COALESCE(station.station_count, 0) as stationCount,
            COALESCE(volume.oil_volume, 0) as oilVolume
        FROM sys_depart d
        LEFT JOIN (
            SELECT
                org_code,
                COUNT(IF(behavior=1, 1, NULL)) as oil_count
            FROM t_oil_record
            <where>
                <if test="startTime != null and startTime != ''">
                    AND start_time &gt;= #{startTime}
                </if>
                <if test="endTime != null and endTime != ''">
                    AND start_time &lt; #{endTime}
                </if>
            </where>
            GROUP BY org_code
        ) oil ON d.org_code = oil.org_code
        LEFT JOIN (
            SELECT
                org_code,
                SUM(car_count) as car_count
            FROM t_traffic_flow
            <where>
                <if test="startTime != null and startTime != ''">
                    AND capture_time &gt;= #{startTime}
                </if>
                <if test="endTime != null and endTime != ''">
                    AND capture_time &lt; #{endTime}
                </if>
            </where>
            GROUP BY org_code
        ) traffic ON d.org_code = traffic.org_code
        LEFT JOIN (
            SELECT
                org_code,
                COUNT(1) as station_count
            FROM t_oil_record
            <where>
                <if test="startTime != null and startTime != ''">
                    AND start_time &gt;= #{startTime}
                </if>
                <if test="endTime != null and endTime != ''">
                    AND start_time &lt; #{endTime}
                </if>
            </where>
            GROUP BY org_code
        ) station ON d.org_code = station.org_code
        LEFT JOIN (
            SELECT
                org_code,
                SUM(oil_volume) as oil_volume
            FROM t_oil_record
            <where>
                <if test="startTime != null and startTime != ''">
                    AND start_time &gt;= #{startTime}
                </if>
                <if test="endTime != null and endTime != ''">
                    AND start_time &lt; #{endTime}
                </if>
            </where>
            GROUP BY org_code
        ) volume ON d.org_code = volume.org_code
        WHERE d.org_code LIKE CONCAT(#{orgCode}, '%')
        GROUP BY d.id, d.org_code, d.depart_name
    </select>
</mapper>
jyz-base-start/src/main/resources/xml/OilRecordMapper.xml
@@ -52,7 +52,7 @@
        select
        oil_position oilPosition, count(1) oilCount,  sum(oil_volume) OilVolume
        from t_oil_record
        where org_code =#{orgCode}
        where org_code like concat(#{orgCode}, '%')
        <if test="dateMonth != null and dateMonth != ''">and DATE_FORMAT(start_time, '%Y-%m')=#{dateMonth}</if>
        GROUP BY oil_position
    </select>
@@ -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
        *,
@@ -104,7 +120,8 @@
            count(if(behavior=1,1,null)) oilCount,
            sum(oil_volume) oilVolume,
            sum(spand_time) sumSpand,
            count(DISTINCT if(behavior=1, r.license_num, null)) onceOilCount
            count(DISTINCT if(behavior=1, r.license_num, null)) onceOilCount,
            sum(if(behavior=1, total_amount, 0)) totalAmount
            from t_oil_record r
            join (
            select sum(car_count) carCount from t_traffic_flow
@@ -183,6 +200,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,
@@ -220,4 +269,55 @@
          GROUP BY model_code
        ) f on m.model_code = f.model_code
    </select>
    <select id="statFanByOilType" resultType="com.tievd.jyz.entity.vo.StatDataTableVo" parameterType="com.tievd.jyz.entity.vo.DataStatisReqVo">
        select
        count(if(behavior=1,1,null)) oilCount,
        sum(oil_volume) oilVolume,
        sum(if(behavior=1, total_amount, 0)) totalAmount,
        oil_type oilType
        from t_oil_record
        <include refid="statRecordCondition" />
        and oil_type is not null and oil_type != ''
        GROUP BY oil_type
    </select>
    <select id="getVehicleFrequencyBeforeActivity" resultType="java.util.Map">
        SELECT
            COUNT(DISTINCT license_num) as totalVehicles,
            COUNT(*) as totalOilRecords,
            AVG(oil_volume) as avgOilVolume,
            SUM(oil_volume) as totalOilVolume
        FROM t_oil_record
        WHERE start_time &lt; #{startTime}
        <foreach collection="orgCodes" item="orgCode" open="AND (" separator=" OR " close=")">
            org_code LIKE concat(#{orgCode}, '%')
        </foreach>
    </select>
    <select id="getVehicleFrequencyDuringActivity" resultType="java.util.Map">
        SELECT
            COUNT(DISTINCT license_num) as totalVehicles,
            COUNT(*) as totalOilRecords,
            AVG(oil_volume) as avgOilVolume,
            SUM(oil_volume) as totalOilVolume
        FROM t_oil_record
        WHERE start_time >= #{startTime} AND start_time &lt;= #{endTime}
        <foreach collection="orgCodes" item="orgCode" open="AND (" separator=" OR " close=")">
            org_code LIKE concat(#{orgCode}, '%')
        </foreach>
    </select>
    <select id="getVehicleFrequencyAfterActivity" resultType="java.util.Map">
        SELECT
            COUNT(DISTINCT license_num) as totalVehicles,
            COUNT(*) as totalOilRecords,
            AVG(oil_volume) as avgOilVolume,
            SUM(oil_volume) as totalOilVolume
        FROM t_oil_record
        WHERE start_time > #{endTime}
        <foreach collection="orgCodes" item="orgCode" open="AND (" separator=" OR " close=")">
            org_code LIKE concat(#{orgCode}, '%')
        </foreach>
    </select>
</mapper>