| @@ -0,0 +1,35 @@ | |||
| package com.iformall.controller.datatower; | |||
| import com.iformall.annotation.TenantIgnore; | |||
| import com.iformall.common.ResultData; | |||
| import com.iformall.controller.base.BaseController; | |||
| import com.iformall.service.CockpitScreenService; | |||
| import io.swagger.annotations.Api; | |||
| import io.swagger.annotations.ApiOperation; | |||
| 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; | |||
| @Api(description = "驾驶舱大屏") | |||
| @RestController | |||
| @RequestMapping("cockpitscreen") | |||
| public class CockpitScreenController extends BaseController { | |||
| @Autowired | |||
| private CockpitScreenService cockpitScreenService; | |||
| @TenantIgnore | |||
| @ApiOperation("驾驶舱大屏-统计会员性别") | |||
| @GetMapping("/countUserGender") | |||
| public ResultData countUserGender() { | |||
| return new ResultData(cockpitScreenService.countUserGender(getTenantInfo())); | |||
| } | |||
| @TenantIgnore | |||
| @ApiOperation("驾驶舱大屏-统计商铺") | |||
| @GetMapping("/countShop") | |||
| public ResultData countShop() { | |||
| return new ResultData(cockpitScreenService.countShop(getTenantInfo())); | |||
| } | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| package com.iformall.common; | |||
| /** | |||
| * 公用常量 | |||
| * | |||
| * @author xmzhao71 | |||
| * @date 2023-09-20 | |||
| */ | |||
| public interface CommonConstant { | |||
| /** | |||
| * 保留小数位(符合语义的使用) | |||
| */ | |||
| int SCALE_2 = 2; | |||
| int SCALE_3 = 3; | |||
| int SCALE_4 = 4; | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| package com.iformall.domain.dto.cockpit; | |||
| import com.iformall.domain.vo.cockpit.CountShopVO; | |||
| import io.swagger.annotations.ApiModel; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.Data; | |||
| @ApiModel(value = "根据状态统计商铺数量") | |||
| @Data | |||
| public class CountShopByStatusDTO { | |||
| @ApiModelProperty(value = "商铺状态") | |||
| private Integer status; | |||
| @ApiModelProperty(value = "商铺数量") | |||
| private Integer shopCount; | |||
| } | |||
| @@ -0,0 +1,37 @@ | |||
| package com.iformall.domain.dto.cockpit; | |||
| import com.iformall.domain.vo.cockpit.CountUserGenderVO; | |||
| import io.swagger.annotations.ApiModel; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.AllArgsConstructor; | |||
| import lombok.Data; | |||
| import lombok.NoArgsConstructor; | |||
| @ApiModel(value = "根据性别统计会员数量") | |||
| @Data | |||
| @NoArgsConstructor | |||
| @AllArgsConstructor | |||
| public class CountUserByGenderDTO { | |||
| @ApiModelProperty(value = "用户性别") | |||
| private Integer gender; | |||
| @ApiModelProperty(value = "用户数量") | |||
| private Integer userCount; | |||
| public static CountUserGenderVO.CountUserGenderDetailVO mapping(CountUserByGenderDTO dto) { | |||
| CountUserGenderVO.CountUserGenderDetailVO vo = new CountUserGenderVO.CountUserGenderDetailVO(); | |||
| vo.setGender(dto.getGender()); | |||
| vo.setUserCount(dto.getUserCount()); | |||
| return vo; | |||
| } | |||
| private static String acquireGender(Integer gender) { | |||
| switch (gender) { | |||
| case 1: | |||
| return "男"; | |||
| case 2: | |||
| return "女"; | |||
| default: | |||
| return "不详"; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| package com.iformall.domain.vo.cockpit; | |||
| import io.swagger.annotations.ApiModel; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.Data; | |||
| import java.math.BigDecimal; | |||
| @ApiModel(value = "商铺统计返回数据") | |||
| @Data | |||
| public class CountShopVO { | |||
| @ApiModelProperty(value = "总的商铺数量") | |||
| private Integer totalShopCount; | |||
| @ApiModelProperty(value = "出租的商铺数量") | |||
| private Integer rentedShopCount; | |||
| @ApiModelProperty(value = "出租的商铺数量比例") | |||
| private BigDecimal rentedShopCountRatio; | |||
| @ApiModelProperty(value = "未出租的商铺数量") | |||
| private Integer unRentedShopCount; | |||
| @ApiModelProperty(value = "未出租的商铺数量比例") | |||
| private BigDecimal unRentedShopCountRatio; | |||
| } | |||
| @@ -0,0 +1,29 @@ | |||
| package com.iformall.domain.vo.cockpit; | |||
| import io.swagger.annotations.ApiModel; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.Data; | |||
| import java.math.BigDecimal; | |||
| import java.util.List; | |||
| @ApiModel(value = "会员性别统计返回数据") | |||
| @Data | |||
| public class CountUserGenderVO { | |||
| @ApiModelProperty(value = "总的会员数量") | |||
| private Integer totalUserCount; | |||
| @ApiModelProperty(value = "会员数量详情") | |||
| private List<CountUserGenderDetailVO> userGenderDetails; | |||
| @ApiModel(value = "会员性别统计详情返回数据") | |||
| @Data | |||
| public static class CountUserGenderDetailVO { | |||
| @ApiModelProperty(value = "性别:0:不详 1:男 2:女") | |||
| private Integer gender; | |||
| @ApiModelProperty(value = "每个性别的数量") | |||
| private Integer userCount; | |||
| @ApiModelProperty(value = "每个性别的比例") | |||
| private BigDecimal userCountRatio; | |||
| } | |||
| } | |||
| @@ -0,0 +1,40 @@ | |||
| package com.iformall.enums; | |||
| /** | |||
| * 用户性别枚举 | |||
| * | |||
| * @author xmzhao71 | |||
| * @date 2023-09-20 | |||
| */ | |||
| public enum EnumUserGender { | |||
| GENDER_UNKNOWN(0, "不详"), | |||
| GENDER_MALE(1, "男"), | |||
| GENDER_FEMALE(2, "女"), | |||
| ; | |||
| public static EnumUserGender getEnum(Integer code) { | |||
| for (EnumUserGender value : values()) { | |||
| if (value.getCode().equals(code)) { | |||
| return value; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| private Integer code; | |||
| private String desc; | |||
| EnumUserGender(Integer code, String desc) { | |||
| this.code = code; | |||
| this.desc = desc; | |||
| } | |||
| public Integer getCode() { | |||
| return code; | |||
| } | |||
| public String getDesc() { | |||
| return desc; | |||
| } | |||
| } | |||
| @@ -2,10 +2,12 @@ package com.iformall.mapper; | |||
| import com.iformall.common.CommonMapper; | |||
| import com.iformall.domain.dto.WxCUserBasicInfoDto; | |||
| import com.iformall.domain.dto.cockpit.CountUserByGenderDTO; | |||
| import com.iformall.domain.po.WxCUserBasicInfo; | |||
| import com.iformall.domain.vo.CUserBaseVo; | |||
| import com.iformall.domain.vo.UserCountVo; | |||
| import com.iformall.domain.vo.WxCUserBasicInfoVo; | |||
| import com.iformall.domain.vo.cockpit.CountUserGenderVO; | |||
| import org.apache.ibatis.annotations.Param; | |||
| import java.util.List; | |||
| @@ -64,5 +66,12 @@ public interface WxCUserBasicInfoMapper extends CommonMapper<WxCUserBasicInfo, S | |||
| List<Long> findIdByFilter(WxCUserBasicInfoDto wxCUserBasicInfoDto); | |||
| long getTotalCreditAmount(@Param("tenantId")String tenantId, @Param("finalTenantId")String finalTenantId); | |||
| /** | |||
| * 通过性别统计用户 | |||
| * | |||
| * @param finalTenantId | |||
| */ | |||
| List<CountUserByGenderDTO> countUserByGender(@Param("finalTenantId") String finalTenantId); | |||
| } | |||
| @@ -1,6 +1,7 @@ | |||
| package com.iformall.mapper; | |||
| import com.iformall.common.CommonMapper; | |||
| import com.iformall.domain.dto.cockpit.CountShopByStatusDTO; | |||
| import com.iformall.domain.po.WxShop; | |||
| import com.iformall.domain.vo.WxShopVo; | |||
| import org.apache.ibatis.annotations.Param; | |||
| @@ -47,4 +48,6 @@ public interface WxShopMapper extends CommonMapper<WxShop, String> { | |||
| List<WxShopVo> newFindShopVoList(@Param("tenantId")String tenantId, @Param("shopIds")List<Long> shopIds); | |||
| long findCount(WxShop wxShop); | |||
| List<CountShopByStatusDTO> countShopByStatus(@Param("tenantIds") List<String> tenantIds); | |||
| } | |||
| @@ -0,0 +1,17 @@ | |||
| package com.iformall.service; | |||
| import com.iformall.domain.po.base.TenantEntity; | |||
| import com.iformall.domain.vo.cockpit.CountShopVO; | |||
| import com.iformall.domain.vo.cockpit.CountUserGenderVO; | |||
| /** | |||
| * 驾驶舱大屏服务 | |||
| * | |||
| * @author xmzhao71 | |||
| * @date 2023-09-20 | |||
| */ | |||
| public interface CockpitScreenService { | |||
| CountUserGenderVO countUserGender(TenantEntity tenantInfo); | |||
| CountShopVO countShop(TenantEntity tenantInfo); | |||
| } | |||
| @@ -0,0 +1,99 @@ | |||
| package com.iformall.service.impl; | |||
| import com.iformall.common.CommonConstant; | |||
| import com.iformall.domain.dto.cockpit.CountShopByStatusDTO; | |||
| import com.iformall.domain.dto.cockpit.CountUserByGenderDTO; | |||
| import com.iformall.domain.po.base.TenantEntity; | |||
| import com.iformall.domain.vo.cockpit.CountShopVO; | |||
| import com.iformall.domain.vo.cockpit.CountUserGenderVO; | |||
| import com.iformall.enums.EnumShopStatus; | |||
| import com.iformall.enums.EnumUserGender; | |||
| import com.iformall.mapper.WxCUserBasicInfoMapper; | |||
| import com.iformall.mapper.WxShopMapper; | |||
| import com.iformall.service.CockpitScreenService; | |||
| import com.iformall.service.WxCUserBasicInfoService; | |||
| import com.iformall.service.WxMallService; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Service; | |||
| import java.math.BigDecimal; | |||
| import java.math.RoundingMode; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.stream.Collectors; | |||
| /** | |||
| * 驾驶舱大屏服务 | |||
| * | |||
| * @author xmzhao71 | |||
| * @date 2023-09-20 | |||
| */ | |||
| @Service | |||
| public class CockpitScreenServiceImpl implements CockpitScreenService { | |||
| @Autowired | |||
| private WxCUserBasicInfoService cUserBasicInfoService; | |||
| @Autowired | |||
| private WxCUserBasicInfoMapper cUserBasicInfoMapper; | |||
| @Autowired | |||
| private WxMallService wxMallService; | |||
| @Autowired | |||
| private WxShopMapper wxShopMapper; | |||
| @Override | |||
| public CountUserGenderVO countUserGender(TenantEntity tenantEntity) { | |||
| CountUserGenderVO result = new CountUserGenderVO(); | |||
| List<CountUserByGenderDTO> dtos = cUserBasicInfoMapper.countUserByGender(tenantEntity.getFinalTenantId()); | |||
| List<CountUserByGenderDTO> totalGenders = dtos.stream().filter(x -> | |||
| x.getGender() != null && (x.getGender().equals(EnumUserGender.GENDER_MALE.getCode()) || x.getGender().equals(EnumUserGender.GENDER_FEMALE.getCode())) | |||
| ).collect(Collectors.toList()); | |||
| Integer unknownGender = dtos.stream().filter(x -> | |||
| x.getGender() == null || x.getGender().equals(EnumUserGender.GENDER_UNKNOWN.getCode()) | |||
| ).map(CountUserByGenderDTO::getUserCount).reduce(Integer::sum).orElse(0); | |||
| totalGenders.add(new CountUserByGenderDTO(EnumUserGender.GENDER_UNKNOWN.getCode(), unknownGender)); | |||
| Integer totalUserCount = totalGenders.stream().map(CountUserByGenderDTO::getUserCount).reduce(Integer::sum).orElse(0); | |||
| result.setTotalUserCount(totalUserCount); | |||
| List<CountUserGenderVO.CountUserGenderDetailVO> vos = totalGenders.stream().map(x -> { | |||
| CountUserGenderVO.CountUserGenderDetailVO vo = CountUserByGenderDTO.mapping(x); | |||
| BigDecimal userCountRatio = BigDecimal.valueOf(x.getUserCount()).divide(BigDecimal.valueOf(totalUserCount), CommonConstant.SCALE_4, RoundingMode.HALF_UP); | |||
| vo.setUserCountRatio(userCountRatio); | |||
| return vo; | |||
| }).collect(Collectors.toList()); | |||
| BigDecimal genderRatio = vos.stream().filter(x -> !EnumUserGender.GENDER_UNKNOWN.getCode().equals(x.getGender())).map(CountUserGenderVO.CountUserGenderDetailVO::getUserCountRatio).reduce(BigDecimal::add).orElse(BigDecimal.ZERO); | |||
| vos = vos.stream().map(x -> { | |||
| if (EnumUserGender.GENDER_UNKNOWN.getCode().equals(x.getGender())) { | |||
| x.setUserCountRatio(BigDecimal.ONE.subtract(genderRatio)); | |||
| } | |||
| return x; | |||
| }).collect(Collectors.toList()); | |||
| result.setUserGenderDetails(vos); | |||
| return result; | |||
| } | |||
| @Override | |||
| public CountShopVO countShop(TenantEntity tenantInfo) { | |||
| CountShopVO result = new CountShopVO(); | |||
| List<TenantEntity> tenantInfos = wxMallService.getTenantEntitys(tenantInfo); | |||
| List<String> tenantIds = tenantInfos.stream().map(TenantEntity::getTenantId).collect(Collectors.toList()); | |||
| List<CountShopByStatusDTO> dtos = wxShopMapper.countShopByStatus(tenantIds); | |||
| Map<Integer, Integer> shopMap = dtos.stream().collect(Collectors.toMap(CountShopByStatusDTO::getStatus, CountShopByStatusDTO::getShopCount)); | |||
| Integer totalShopCount = dtos.stream().map(CountShopByStatusDTO::getShopCount).reduce(Integer::sum).orElse(0); | |||
| result.setTotalShopCount(totalShopCount); | |||
| Integer rentedShopCount = shopMap.get(EnumShopStatus.RENT.getCode()); | |||
| Integer unRentedShopCount = shopMap.get(EnumShopStatus.NOT_RENT.getCode()); | |||
| result.setRentedShopCount(rentedShopCount); | |||
| result.setUnRentedShopCount(unRentedShopCount); | |||
| BigDecimal rentedShopCountRatio = BigDecimal.valueOf(rentedShopCount).divide(BigDecimal.valueOf(totalShopCount), CommonConstant.SCALE_4, RoundingMode.HALF_UP); | |||
| result.setRentedShopCountRatio(rentedShopCountRatio); | |||
| result.setUnRentedShopCountRatio(BigDecimal.ONE.subtract(rentedShopCountRatio)); | |||
| return result; | |||
| } | |||
| } | |||
| @@ -570,6 +570,12 @@ | |||
| and wcubi.`tenant_id` like concat('%,', #{tenantId},',%') | |||
| </if> | |||
| </select> | |||
| <select id="countUserByGender" resultType="com.iformall.domain.dto.cockpit.CountUserByGenderDTO"> | |||
| SELECT sex AS gender, COUNT(id) AS userCount | |||
| FROM wx_c_user_basic_info | |||
| WHERE final_tenant_id = #{finalTenantId} | |||
| GROUP BY sex; | |||
| </select> | |||
| <update id="incActRecordById" parameterType="java.util.HashMap"> | |||
| @@ -619,4 +619,17 @@ | |||
| </foreach> | |||
| </if> | |||
| </select> | |||
| <select id="countShopByStatus" resultType="com.iformall.domain.dto.cockpit.CountShopByStatusDTO"> | |||
| SELECT `status` AS status, COUNT(id) AS shopCount | |||
| FROM wx_shop | |||
| WHERE | |||
| <if test="null != tenantIds and tenantIds.size() > 0"> | |||
| tenant_id in | |||
| <foreach collection="tenantIds" index="index" item="tenantId" open="(" separator="," close=")"> | |||
| #{tenantId} | |||
| </foreach> | |||
| </if> | |||
| GROUP BY `status`; | |||
| </select> | |||
| </mapper> | |||