diff --git a/ad-distribute-common/common-core/src/main/java/com/baiye/enums/ChannelTypeEnum.java b/ad-distribute-common/common-core/src/main/java/com/baiye/enums/ChannelTypeEnum.java new file mode 100644 index 0000000..27f82fb --- /dev/null +++ b/ad-distribute-common/common-core/src/main/java/com/baiye/enums/ChannelTypeEnum.java @@ -0,0 +1,50 @@ +package com.baiye.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author wjt + * @date 2023/12/7 + */ +@Getter +@AllArgsConstructor +public enum ChannelTypeEnum { + /** + * 手动创建 + */ + MANUAL_CREATE(1, "手动创建"), + /** + * 文件上传 + */ + FILE_UPLOAD(2, "文件上传"), + + /** + * 飞鱼回传 + */ + FEI_YU(3, "飞鱼回传"), + + /** + * 话单回传 + */ + FORM(4, "话单回传"), + + /** + * api回传 + */ + API(5, "api回传"), + ; + + + private final Integer key; + private final String name; + + public static String find(Integer key) { + for (ChannelTypeEnum channelTypeEnum : ChannelTypeEnum.values()) { + if (channelTypeEnum.key.equals(key)) { + return channelTypeEnum.name; + } + } + return null; + } +} diff --git a/admin/src/main/java/com/baiye/modules/distribute/controller/HomepageController.java b/admin/src/main/java/com/baiye/modules/distribute/controller/HomepageController.java new file mode 100644 index 0000000..7d6061c --- /dev/null +++ b/admin/src/main/java/com/baiye/modules/distribute/controller/HomepageController.java @@ -0,0 +1,50 @@ +package com.baiye.modules.distribute.controller; + +import com.baiye.modules.distribute.qo.HomePageQo; +import com.baiye.modules.distribute.service.HomepageService; +import com.baiye.result.R; +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; + +/** + * @author wjt + * @date 2023/12/6 + * 首页统计 + */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/homePage") +public class HomepageController { + + private final HomepageService homepageService; + + @GetMapping("/base") + @Operation(description = "今日实时") + public R baseCount() { + return R.ok(homepageService.baseCount()); + } + + + @PostMapping("/enter") + @Operation(description = "渠道录入") + public R channelEnterClue(@RequestBody HomePageQo homePageQo) { + return R.ok(homepageService.channelEnterClue(homePageQo)); + } + + @PostMapping("/assigned") + @Operation(description = "渠道分发") + public R channelAssignedClue(@RequestBody HomePageQo homePageQo) { + return R.ok(homepageService.channelAssignedClue(homePageQo)); + } + + @PostMapping("/export") + @Operation(summary = "导出") + public void channelClueExport(HttpServletResponse response, @RequestBody HomePageQo homePageQo) { + homepageService.channelClueExport(response, homePageQo); + } +} diff --git a/admin/src/main/java/com/baiye/modules/distribute/dto/HomePageDTO.java b/admin/src/main/java/com/baiye/modules/distribute/dto/HomePageDTO.java new file mode 100644 index 0000000..aaed6cf --- /dev/null +++ b/admin/src/main/java/com/baiye/modules/distribute/dto/HomePageDTO.java @@ -0,0 +1,21 @@ +package com.baiye.modules.distribute.dto; + +import lombok.Data; + +/** + * @author wjt + * @date 2023/12/6 + */ +@Data +public class HomePageDTO { + + private String createTime; + + private Long assignedBy; + + private String assignedName; + + private Long createBy; + + private String enterName; +} diff --git a/admin/src/main/java/com/baiye/modules/distribute/mapper/ClueMapper.java b/admin/src/main/java/com/baiye/modules/distribute/mapper/ClueMapper.java index de4852c..8cbf279 100644 --- a/admin/src/main/java/com/baiye/modules/distribute/mapper/ClueMapper.java +++ b/admin/src/main/java/com/baiye/modules/distribute/mapper/ClueMapper.java @@ -4,9 +4,11 @@ import com.baiye.domain.PageParam; import com.baiye.domain.PageResult; import com.baiye.extend.mybatis.plus.conditions.query.LambdaAliasQueryWrapperX; import com.baiye.extend.mybatis.plus.toolkit.WrappersX; +import com.baiye.modules.distribute.dto.HomePageDTO; import com.baiye.modules.distribute.entity.ClueEntity; import com.baiye.extend.mybatis.plus.mapper.ExtendMapper; import com.baiye.modules.distribute.qo.ClueQo; +import com.baiye.modules.distribute.qo.HomePageQo; import com.baiye.modules.distribute.vo.ClueVO; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -41,4 +43,8 @@ public interface ClueMapper extends ExtendMapper { IPage selectByPage(IPage page, @Param(Constants.WRAPPER) Wrapper wrapper); + + List selectDetailByChannelAndAssigned(@Param("qo") HomePageQo homePageQo); + + Integer addCount(@Param("date") String date, @Param("companyId") Long companyId); } diff --git a/admin/src/main/java/com/baiye/modules/distribute/mapper/CustomMapper.java b/admin/src/main/java/com/baiye/modules/distribute/mapper/CustomMapper.java index dc01bcb..03a9af9 100644 --- a/admin/src/main/java/com/baiye/modules/distribute/mapper/CustomMapper.java +++ b/admin/src/main/java/com/baiye/modules/distribute/mapper/CustomMapper.java @@ -5,8 +5,10 @@ import com.baiye.domain.PageResult; import com.baiye.extend.mybatis.plus.conditions.query.LambdaAliasQueryWrapperX; import com.baiye.extend.mybatis.plus.mapper.ExtendMapper; import com.baiye.extend.mybatis.plus.toolkit.WrappersX; +import com.baiye.modules.distribute.dto.HomePageDTO; import com.baiye.modules.distribute.entity.CustomEntity; import com.baiye.modules.distribute.qo.CustomQo; +import com.baiye.modules.distribute.qo.HomePageQo; import com.baiye.modules.distribute.vo.CustomVO; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -14,6 +16,8 @@ import com.baomidou.mybatisplus.core.toolkit.Constants; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import org.apache.ibatis.annotations.Param; +import java.util.List; + public interface CustomMapper extends ExtendMapper { default PageResult queryPage(PageParam pageParam, CustomQo qo) { IPage page = this.prodPage(pageParam); @@ -46,5 +50,9 @@ public interface CustomMapper extends ExtendMapper { /** * 查询最大编号 */ - String selectMaxBatchNoByCompanyId(@Param("code") String code,@Param("companyId") Long companyId); + String selectMaxBatchNoByCompanyId(@Param("code") String code, @Param("companyId") Long companyId); + + List selectByCompanyIdAndTime(@Param("qo") HomePageQo homePageQo); + + List addCount(@Param("date") String date, @Param("companyId") Long companyId); } diff --git a/admin/src/main/java/com/baiye/modules/distribute/qo/HomePageQo.java b/admin/src/main/java/com/baiye/modules/distribute/qo/HomePageQo.java new file mode 100644 index 0000000..3711219 --- /dev/null +++ b/admin/src/main/java/com/baiye/modules/distribute/qo/HomePageQo.java @@ -0,0 +1,39 @@ +package com.baiye.modules.distribute.qo; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springdoc.api.annotations.ParameterObject; + +import java.util.List; + +/** + * @author wjt + * @date 2023/12/6 + */ +@Data +@Schema(title = "首页") +@ParameterObject +public class HomePageQo { + + @Parameter(description = "公司id") + private Long companyId; + + @Parameter(description = "添加的开始时间") + private String createStartTime; + + @Parameter(description = "添加的结束时间") + private String createEndTime; + + @Parameter(description = "分配的客户id") + private List assignedIdList; + + @Parameter(description = "录入员id") + private List enterIdList; + + @Parameter(description = "渠道类型(1 手动创建 2文件上传 3飞鱼回传 4话单回传 5 api回传)") + private Integer channelType; + + @Parameter(description = "下载类型 1- 录入 2-分发") + private Integer type; +} diff --git a/admin/src/main/java/com/baiye/modules/distribute/service/HomepageService.java b/admin/src/main/java/com/baiye/modules/distribute/service/HomepageService.java new file mode 100644 index 0000000..a799f4c --- /dev/null +++ b/admin/src/main/java/com/baiye/modules/distribute/service/HomepageService.java @@ -0,0 +1,45 @@ +package com.baiye.modules.distribute.service; + +import com.baiye.modules.distribute.qo.HomePageQo; + +import javax.servlet.http.HttpServletResponse; +import java.util.Map; + +/** + * @author wjt + * @date 2023/12/6 + */ +public interface HomepageService { + + /** + * 基础统计 + * + * @return 统计信息 + */ + Map baseCount(); + + /** + * 渠道进线统计 + * + * @param homePageQo 条件 + * @return 统计信息 + */ + Map> channelEnterClue(HomePageQo homePageQo); + + /** + * 导出 渠道进线统计 + * + * @param response + * @param homePageQo + */ + void channelClueExport(HttpServletResponse response, HomePageQo homePageQo); + + /** + * 渠道详细统计 + * + * @param homePageQo 条件 + * @return 统计信息 + */ + Map> channelAssignedClue(HomePageQo homePageQo); + +} diff --git a/admin/src/main/java/com/baiye/modules/distribute/service/impl/HomepageServiceImpl.java b/admin/src/main/java/com/baiye/modules/distribute/service/impl/HomepageServiceImpl.java new file mode 100644 index 0000000..38d45f7 --- /dev/null +++ b/admin/src/main/java/com/baiye/modules/distribute/service/impl/HomepageServiceImpl.java @@ -0,0 +1,221 @@ +package com.baiye.modules.distribute.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.poi.excel.ExcelUtil; +import cn.hutool.poi.excel.ExcelWriter; +import com.baiye.enums.ChannelTypeEnum; +import com.baiye.exception.BadRequestException; +import com.baiye.modules.distribute.dto.HomePageDTO; +import com.baiye.modules.distribute.mapper.ClueMapper; +import com.baiye.modules.distribute.mapper.CustomMapper; +import com.baiye.modules.distribute.qo.HomePageQo; +import com.baiye.modules.distribute.service.HomepageService; +import com.baiye.modules.distribute.vo.ChannelAssignedClueExportVo; +import com.baiye.modules.distribute.vo.ChannelEnterClueExportVO; +import com.baiye.security.util.SecurityUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author wjt + * @date 2023/12/6 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class HomepageServiceImpl implements HomepageService { + + private final ClueMapper clueMapper; + private final CustomMapper customMapper; + + + @Override + public Map baseCount() { + //进线 + List list = customMapper.addCount(DateUtil.format(DateUtil.date(), "yyyy-MM-dd"), SecurityUtils.getCurrentUserId()); + //分发 + Integer assignedNum = clueMapper.addCount(DateUtil.format(DateUtil.date(), "yyyy-MM-dd"), SecurityUtils.getCurrentUserId()); + //进线数 + Integer enterNum = 0; + //分发率 + double assignedRate = 0.0; + //重审数 + int reviewNum = 0; + if (CollUtil.isNotEmpty(list)) { + enterNum = list.size(); + assignedRate = NumberUtil.div(assignedNum, enterNum).doubleValue(); + reviewNum = (int) list.stream().filter(type -> type == 3).count(); + } + Map map = new HashMap<>(16); + map.put("enterNum", enterNum); + map.put("assignedNum", assignedNum); + map.put("reviewNum", reviewNum); + map.put("assignedRate", assignedRate); + return map; + } + + @Override + public Map> channelEnterClue(HomePageQo homePageQo) { + Long currentUserId = SecurityUtils.getCurrentUserId(); + homePageQo.setCompanyId(currentUserId); + List homePageDTO = customMapper.selectByCompanyIdAndTime(homePageQo); + if (CollUtil.isEmpty(homePageDTO)) { + return null; + } + //按录入员分组 + Map> homePageByChannelType = homePageDTO.stream() + .collect(Collectors.groupingBy(HomePageDTO::getEnterName)); + return dealDateSource(homePageByChannelType, homePageQo); + } + + @Override + public void channelClueExport(HttpServletResponse response, HomePageQo homePageQo) { + Long currentUserId = SecurityUtils.getCurrentUserId(); + homePageQo.setCompanyId(currentUserId); + if (homePageQo.getType() == 1) { + channelEnterClueExport(response, homePageQo); + } else { + channelAssignedClueExport(response, homePageQo); + } + } + + private void channelEnterClueExport(HttpServletResponse response, HomePageQo homePageQo) { + List homePageDTO = customMapper.selectByCompanyIdAndTime(homePageQo); + if (CollUtil.isEmpty(homePageDTO)) { + return; + } + //渠道商 + String channelType = ChannelTypeEnum.find(homePageQo.getChannelType()); + List list = new ArrayList<>(); + //按录入员分组 + Map> homePageByChannelType = homePageDTO.stream() + .collect(Collectors.groupingBy(HomePageDTO::getEnterName)); + for (Map.Entry> entry : homePageByChannelType.entrySet()) { + //录入员 + String key = entry.getKey(); + List value = entry.getValue(); + //按时间分组 + Map> collect = value.stream().collect(Collectors.groupingBy(HomePageDTO::getCreateTime)); + + for (Map.Entry> map : collect.entrySet()) { + String time = map.getKey(); + int size = map.getValue().size(); + ChannelEnterClueExportVO channelEnterClueExportVO = new ChannelEnterClueExportVO(); + channelEnterClueExportVO.setChannelType(channelType); + channelEnterClueExportVO.setEnterBy(key); + channelEnterClueExportVO.setDate(time); + channelEnterClueExportVO.setNum(size); + list.add(channelEnterClueExportVO); + } + } + //导出 + try { + ExcelWriter writer = ExcelUtil.getWriter(); + writer.write(list, true); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment;filename=export.xlsx"); + ServletOutputStream out = response.getOutputStream(); + writer.flush(out, true); + writer.close(); + IoUtil.close(out); + } catch (Exception e) { + throw new BadRequestException("导出失败"); + } + } + + @Override + public Map> channelAssignedClue(HomePageQo homePageQo) { + Long currentUserId = SecurityUtils.getCurrentUserId(); + homePageQo.setCompanyId(currentUserId); + List homePageDTO = clueMapper.selectDetailByChannelAndAssigned(homePageQo); + if (CollUtil.isEmpty(homePageDTO)) { + return null; + } + //按分配人分组 + Map> homePageByAssigned = homePageDTO.stream() + .collect(Collectors.groupingBy(HomePageDTO::getAssignedName)); + return dealDateSource(homePageByAssigned, homePageQo); + } + + public void channelAssignedClueExport(HttpServletResponse response, HomePageQo homePageQo) { + List homePageDTO = clueMapper.selectDetailByChannelAndAssigned(homePageQo); + if (CollUtil.isEmpty(homePageDTO)) { + return; + } + //渠道商 + String channelType = ChannelTypeEnum.find(homePageQo.getChannelType()); + List list = new ArrayList<>(); + //按分配人分组 + Map> homePageByAssigned = homePageDTO.stream() + .collect(Collectors.groupingBy(HomePageDTO::getAssignedName)); + for (Map.Entry> entry : homePageByAssigned.entrySet()) { + //分配员 + String key = entry.getKey(); + List value = entry.getValue(); + //按时间分组 + Map> collect = value.stream().collect(Collectors.groupingBy(HomePageDTO::getCreateTime)); + + for (Map.Entry> map : collect.entrySet()) { + String time = map.getKey(); + int size = map.getValue().size(); + ChannelAssignedClueExportVo channelAssignedClueExportVo = new ChannelAssignedClueExportVo(); + channelAssignedClueExportVo.setChannelType(channelType); + channelAssignedClueExportVo.setAssignedBy(key); + channelAssignedClueExportVo.setDate(time); + channelAssignedClueExportVo.setNum(size); + list.add(channelAssignedClueExportVo); + } + } + //导出 + try { + ExcelWriter writer = ExcelUtil.getWriter(); + writer.write(list, true); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment;filename=export.xlsx"); + ServletOutputStream out = response.getOutputStream(); + writer.flush(out, true); + writer.close(); + IoUtil.close(out); + } catch (Exception e) { + throw new BadRequestException("导出失败"); + } + } + + private Map> dealDateSource(Map> homePageList, HomePageQo homePageQo) { + //返回统计值 结构如 {0:{"2023-12-6":100}} + Map> mapChannelType = new HashMap<>(16); + for (Map.Entry> entry : homePageList.entrySet()) { + //录入员名称 + String key = entry.getKey(); + List value = entry.getValue(); + //按时间分组 + Map> homePageByTime = value.stream() + .collect(Collectors.groupingBy(HomePageDTO::getCreateTime)); + long betweenDay = DateUtil.between(DateUtil.parseDate(homePageQo.getCreateStartTime()), DateUtil.parseDate(homePageQo.getCreateEndTime()), DateUnit.DAY); + //返回日期值 如{"2023-12-6":100} + Map mapNum = new LinkedHashMap<>(16); + for (int i = 0; i <= betweenDay; i++) { + String time = DateUtil.format(DateUtil.offsetDay(DateUtil.parseDate(homePageQo.getCreateStartTime()), i), "yyyy-MM-dd"); + if (homePageByTime.containsKey(time)) { + List homePageS = homePageByTime.get(time); + mapNum.put(time, homePageS.size()); + } else { + mapNum.put(time, 0); + } + } + mapChannelType.put(key, mapNum); + } + return mapChannelType; + } +} diff --git a/admin/src/main/java/com/baiye/modules/distribute/vo/ChannelAssignedClueExportVo.java b/admin/src/main/java/com/baiye/modules/distribute/vo/ChannelAssignedClueExportVo.java new file mode 100644 index 0000000..234c766 --- /dev/null +++ b/admin/src/main/java/com/baiye/modules/distribute/vo/ChannelAssignedClueExportVo.java @@ -0,0 +1,21 @@ +package com.baiye.modules.distribute.vo; + +import cn.hutool.core.annotation.Alias; +import lombok.Data; + +/** + * @author wjt + * @date 2023/12/7 + */ +@Data +public class ChannelAssignedClueExportVo { + + @Alias(value = "渠道") + private String channelType; + @Alias(value = "分配人") + private String assignedBy; + @Alias(value = "日期") + private String date; + @Alias(value = "录入量") + private Integer num; +} diff --git a/admin/src/main/java/com/baiye/modules/distribute/vo/ChannelEnterClueExportVO.java b/admin/src/main/java/com/baiye/modules/distribute/vo/ChannelEnterClueExportVO.java new file mode 100644 index 0000000..2c4e610 --- /dev/null +++ b/admin/src/main/java/com/baiye/modules/distribute/vo/ChannelEnterClueExportVO.java @@ -0,0 +1,20 @@ +package com.baiye.modules.distribute.vo; + +import cn.hutool.core.annotation.Alias; +import lombok.Data; + +/** + * @author wjt + * @date 2023/12/7 + */ +@Data +public class ChannelEnterClueExportVO { + @Alias(value = "渠道") + private String channelType; + @Alias(value = "录入员") + private String enterBy; + @Alias(value = "日期") + private String date; + @Alias(value = "录入量") + private Integer num; +} diff --git a/admin/src/main/resources/mapper/ClueMapper.xml b/admin/src/main/resources/mapper/ClueMapper.xml index 37289fd..7ca9ec6 100644 --- a/admin/src/main/resources/mapper/ClueMapper.xml +++ b/admin/src/main/resources/mapper/ClueMapper.xml @@ -2,7 +2,10 @@ - ce.clue_id, + ce + . + clue_id + , ce.is_new_clue, ce.origin_name, ce.nid, @@ -44,4 +47,26 @@ tb_clue ce ${ew.customSqlSegment} + + + + diff --git a/admin/src/main/resources/mapper/CustomMapper.xml b/admin/src/main/resources/mapper/CustomMapper.xml index 8aab893..4c4dc1a 100644 --- a/admin/src/main/resources/mapper/CustomMapper.xml +++ b/admin/src/main/resources/mapper/CustomMapper.xml @@ -2,7 +2,10 @@ - cm.enter_name, + cm + . + enter_name + , cm.custom_id, cm.custom_name, cm.custom_nid, @@ -34,8 +37,29 @@ select batch_no from tb_custom where batch_no like concat(#{code}, '%') - and company_id = #{companyId} + and company_id = #{companyId} order by custom_id desc LIMIT 1 + + +