feat:app统计

This commit is contained in:
dzc committed 2025-08-13 11:47:08 +08:00
1 parent 7584926e62
commit 75033aa225
13 files changed
+418 -6

No files matched your search

@@ -20,11 +20,14 @@
package com.bsd.pjcloud.canteen.api.feign;
import com.bsd.pjcloud.canteen.entity.CanteenCategoryEntity;
import com.bsd.pjcloud.common.core.constant.ServiceNameConstants;
import com.bsd.pjcloud.common.core.util.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author zjf
* @date 2018/6/22
@@ -35,10 +38,8 @@ public interface RemoteCanteenCategoryService {
/**
* 查询所有的菜品分类
* @param categoryType 餐段类型,1早餐 2中 3晚餐 不传默认所有
* @return R
*/
@GetMapping("/canteenCategory/getAllSimple")
R getAllSimple(@RequestParam(value = "categoryType",required = false) String categoryType);
R<List<CanteenCategoryEntity>> getAllSimple(@RequestParam(value = "categoryType", required = false) String categoryType, @RequestParam(value = "name", required = false) String name);
}
@@ -139,7 +139,7 @@ public class CanteenCategoryController {
@Operation(summary = "通过id查询", description = "通过id查询")
@GetMapping("/getAllSimple")
// @PreAuthorize("@pms.hasPermission('canteen_canteenCategory_view')")
public R getAllSimple(@RequestParam(value = "categoryType", required = false) String categoryType,
public R<List<CanteenCategoryEntity>> getAllSimple(@RequestParam(value = "categoryType", required = false) String categoryType,
@RequestParam(value = "name", required = false) String name) {
LambdaQueryWrapper<CanteenCategoryEntity> wrapper = Wrappers.lambdaQuery();
wrapper.like(StringUtils.isNotBlank(name), CanteenCategoryEntity::getName, name);
@@ -0,0 +1,31 @@
package com.bsd.pjcloud.hard.api.constant.total;
import cn.hutool.core.util.ObjectUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 日期范围类型
*/
@AllArgsConstructor
@Getter
public enum DateRangeTypeEnum {
TODAY("1", "本天"),
THIS_WEEK("2", "本周"),
THIS_MONTH("3", "本月"),
CURRENT_SEASON("4", "本季度"),
THIS_YEAR("5", "本年"),
;
private final String type;
private final String description;
public static DateRangeTypeEnum valueOfByType(String type) {
if (ObjectUtil.isEmpty(type)) return null;
return Arrays.stream(values()).filter(v -> ObjectUtil.equals(type, v.getType())).findFirst().get();
}
}
@@ -0,0 +1,26 @@
package com.bsd.pjcloud.hard.api.dto.order.app;
import com.bsd.pjcloud.hard.api.constant.total.DateRangeTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
* 各个食堂菜品购买统计
*/
@Data
public class HardAppProductByCanteenDto {
@Schema(description = "食堂id")
private List<String> canteenIdList;
@Schema(description = "用餐时间段")
private String hourType;
@Schema(description = "购买时间根据dateType运算")
private LocalDate[] payTimeList;
}
@@ -0,0 +1,27 @@
package com.bsd.pjcloud.hard.api.dto.order.app;
import com.bsd.pjcloud.hard.api.constant.total.DateRangeTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* 菜品销量按照分类查询
*/
@Data
public class HardAppProductByClassifyDto {
@Schema(description = "食堂id")
private List<String> canteenIdList;
@Schema(description = "日期类型")
private DateRangeTypeEnum dateType;
@Schema(description = "用餐时间段")
private String hourType;
@Schema(description = "购买时间根据dateType运算")
private LocalDateTime[] payTimeList;
}
@@ -0,0 +1,45 @@
package com.bsd.pjcloud.hard.api.vo.order.app;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 菜品销量按照分类查询
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HardAppProductByCanteenVo {
@Schema(description = "商户id")
private Long canteenId;
@Schema(description = "商户名")
private String canteenName;
@Schema(description = "购买总数")
private Long payCount;
@Schema(description = "购买总金额")
private BigDecimal totalPrice;
@Schema(description = "购买总数量")
private Long timeCount;
@Schema(description = "购买总人数")
private Long payUserCount;
@Schema(description = "时间")
private LocalDate time;
@Schema(description = "周几")
private String weekStr;
}
@@ -0,0 +1,32 @@
package com.bsd.pjcloud.hard.api.vo.order.app;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 菜品销量按照分类查询
*/
@Data
public class HardAppProductByClassifyVo {
@Schema(description = "分类id")
private Long classifyId;
@Schema(description = "分类名")
private String classifyName;
@Schema(description = "购买总数")
private Long payCount;
@Schema(description = "购买总金额")
private BigDecimal totalPrice;
@Schema(description = "购买总数量")
private Long timeCount;
@Schema(description = "购买总人数")
private Long payUserCount;
}
@@ -3,10 +3,15 @@ package com.bsd.pjcloud.hard.controller.order;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.security.annotation.Inner;
import com.bsd.pjcloud.hard.api.dto.order.HardCarDto;
import com.bsd.pjcloud.hard.api.dto.order.app.HardAppProductByCanteenDto;
import com.bsd.pjcloud.hard.api.dto.order.app.HardAppProductByClassifyDto;
import com.bsd.pjcloud.hard.api.vo.order.HardCanteenProductTotalVo;
import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto;
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
import com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByCanteenVo;
import com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByClassifyVo;
import com.bsd.pjcloud.hard.service.HardCanteenTotalService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -30,6 +35,28 @@ public class HardCanteenTotalController {
private final HardCanteenTotalService canteenTotalService;
/* ************************************* start app start ************************************* */
/**
* 菜品销量按照分类查询
*/
@Operation(summary = "菜品销量按照分类查询", description = "菜品销量按照分类查询")
@PostMapping("/app/product-by-classify")
public R<List<HardAppProductByClassifyVo>> productByClassify(@RequestBody HardAppProductByClassifyDto dto) {
return R.ok(canteenTotalService.productByClassify(dto));
}
/**
* 近一周各个食堂菜品购买统计
*/
@Inner(value = false)
@Operation(summary = "近一周各个食堂菜品购买统计", description = "近一周各个食堂菜品购买统计")
@PostMapping("/app/product-by-canteen")
public R<List<HardAppProductByCanteenVo>> productByCanteen(@RequestBody HardAppProductByCanteenDto dto) {
return R.ok(canteenTotalService.productByCanteen(dto));
}
/* ************************************* start app start ************************************* */
@Operation(summary = "根据部门 食堂菜品购买统计", description = "根据部门 食堂菜品购买统计")
@PostMapping("/proudct-total-by-dept")
public R<List<HardCanteenProductTotalVo>> productTotalByDept(@ParameterObject Page page, @RequestBody HardOrderDto dto) {
@@ -3,11 +3,15 @@ package com.bsd.pjcloud.hard.mapper.order;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
import com.bsd.pjcloud.hard.api.dto.order.app.HardAppProductByCanteenDto;
import com.bsd.pjcloud.hard.api.dto.order.app.HardAppProductByClassifyDto;
import com.bsd.pjcloud.hard.api.vo.order.HardCanteenProductTotalVo;
import com.bsd.pjcloud.hard.api.dto.order.HardCarDto;
import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto;
import com.bsd.pjcloud.hard.api.entity.order.HardCarEntity;
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
import com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByCanteenVo;
import com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByClassifyVo;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -33,4 +37,14 @@ public interface HardCarMapper extends PjcloudBaseMapper<HardCarEntity> {
List<HardCanteenProductTotalVo> listByDept(@Param("dto") HardOrderDto dto, DataScope dataScope);
List<HardCanteenProductTotalVo> listByHourType(@Param("dto") HardOrderDto dto);
/**
* 菜品销量按照分类查询
*/
List<HardAppProductByClassifyVo> productByClassify(@Param("dto") HardAppProductByClassifyDto dto);
/**
* 各个食堂菜品购买统计
*/
List<HardAppProductByCanteenVo> productByCanteen(@Param("dto") HardAppProductByCanteenDto dto);
}
@@ -4,14 +4,28 @@ package com.bsd.pjcloud.hard.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.hard.api.dto.order.HardCarDto;
import com.bsd.pjcloud.hard.api.dto.order.app.HardAppProductByCanteenDto;
import com.bsd.pjcloud.hard.api.dto.order.app.HardAppProductByClassifyDto;
import com.bsd.pjcloud.hard.api.vo.order.HardCanteenProductTotalVo;
import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto;
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
import com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByCanteenVo;
import com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByClassifyVo;
import java.util.List;
public interface HardCanteenTotalService {
/**
* 菜品销量按照分类查询
*/
List<HardAppProductByClassifyVo> productByClassify(HardAppProductByClassifyDto dto);
/**
* 近一周各个食堂菜品购买统计
*/
List<HardAppProductByCanteenVo> productByCanteen(HardAppProductByCanteenDto dto);
/**
* 根据部门 食堂菜品购买统计
*/
@@ -31,5 +45,4 @@ public interface HardCanteenTotalService {
* 食堂菜品购买部门统计
*/
List<HardCanteenProductTotalVo> listByDept(HardOrderDto dto, DataScope dataScope);
}
@@ -1,17 +1,25 @@
package com.bsd.pjcloud.hard.service.impl.order;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
import com.bsd.pjcloud.canteen.api.feign.RemoteCanteenCategoryService;
import com.bsd.pjcloud.canteen.entity.CanteenCategoryEntity;
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum;
import com.bsd.pjcloud.hard.api.constant.total.DateRangeTypeEnum;
import com.bsd.pjcloud.hard.api.dto.order.HardCarDto;
import com.bsd.pjcloud.hard.api.dto.order.app.HardAppProductByCanteenDto;
import com.bsd.pjcloud.hard.api.dto.order.app.HardAppProductByClassifyDto;
import com.bsd.pjcloud.hard.api.vo.order.HardCanteenProductTotalVo;
import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto;
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
import com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByCanteenVo;
import com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByClassifyVo;
import com.bsd.pjcloud.hard.mapper.order.HardCarMapper;
import com.bsd.pjcloud.hard.mapper.order.HardOrderMapper;
import com.bsd.pjcloud.hard.service.HardCanteenTotalService;
@@ -22,13 +30,19 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
@@ -48,6 +62,57 @@ public class HardCanteenTotalServiceImpl implements HardCanteenTotalService {
private final RemoteDeptService remoteDeptService;
private final RemoteMchService remoteMchService;
private final RemoteCanteenCategoryService canteenCategoryService;
/**
* 菜品销量按照分类查询
*/
@Override
public List<HardAppProductByClassifyVo> productByClassify(HardAppProductByClassifyDto dto) {
if (ObjectUtil.isNotEmpty(dto.getDateType())) {
LocalDateTime[] payTimeList = transitionDateTypeToTimeList(dto.getDateType());
if (ObjectUtil.isNotEmpty(payTimeList)) dto.setPayTimeList(payTimeList);
}
List<HardAppProductByClassifyVo> totalList = hardCarMapper.productByClassify(dto);
// 处理一下
disposeProductByClassify(totalList);
return totalList;
}
/**
* 近一周各个食堂菜品购买统计
*/
@Override
public List<HardAppProductByCanteenVo> productByCanteen(HardAppProductByCanteenDto dto) {
dto.setPayTimeList(new LocalDate[]{LocalDate.now().minusWeeks(1), LocalDate.now()});
// 查询近一周的时间
List<HardAppProductByCanteenVo> dateList = new LinkedList<>();
LocalDate startTime = dto.getPayTimeList()[0];
LocalDate endTime = dto.getPayTimeList()[1];
LocalDate currentDate = startTime;
while (!currentDate.isAfter(endTime)) {
HardAppProductByCanteenVo entity = HardAppProductByCanteenVo.builder().payCount(0L).totalPrice(BigDecimal.ZERO).timeCount(0L).payUserCount(0L).time(currentDate).weekStr(LocalDateTimeUtil.dayOfWeek(currentDate).toChinese()).build();
dateList.add(entity);
currentDate = currentDate.plusDays(1);
}
List<HardAppProductByCanteenVo> totalList = hardCarMapper.productByCanteen(dto);
if (ObjectUtil.isNotEmpty(totalList)) {
for (HardAppProductByCanteenVo vo : totalList) {
if (ObjectUtil.isEmpty(vo.getTime())) continue;
dateList.stream().filter(item -> ObjectUtil.equals(item.getTime(), vo.getTime())).findFirst().ifPresent(target -> {
target.setCanteenId(vo.getCanteenId());
target.setPayCount(vo.getPayCount());
target.setTotalPrice(vo.getTotalPrice());
target.setTimeCount(vo.getTimeCount());
target.setPayUserCount(vo.getPayUserCount());
});
}
}
// 处理一下
disposeProductByCanteen(dateList);
return dateList;
}
/**
* 根据部门 食堂菜品购买统计
*/
@@ -172,4 +237,72 @@ public class HardCanteenTotalServiceImpl implements HardCanteenTotalService {
}
}
}
private LocalDateTime[] transitionDateTypeToTimeList(DateRangeTypeEnum dateType) {
LocalDateTime now = LocalDateTime.now();
switch (dateType) {
case TODAY:
return new LocalDateTime[]{
LocalDateTime.now().withHour(0).withMinute(0).withSecond(0),
LocalDateTime.now().withHour(23).withMinute(59).withSecond(59)
};
case THIS_WEEK:
LocalDateTime weekStart = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).withHour(0).withMinute(0).withSecond(0);
LocalDateTime weekEnd = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)).withHour(23).withMinute(59).withSecond(59);
return new LocalDateTime[]{weekStart, weekEnd};
case THIS_MONTH:
LocalDateTime monthStart = now.with(TemporalAdjusters.firstDayOfMonth()).withHour(0).withMinute(0).withSecond(0);
LocalDateTime monthEnd = now.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59);
return new LocalDateTime[]{monthStart, monthEnd};
case CURRENT_SEASON:
LocalDateTime quarterStart = now.with(now.getMonth().firstMonthOfQuarter()).with(TemporalAdjusters.firstDayOfMonth()).withHour(0).withMinute(0).withSecond(0);
LocalDateTime quarterEnd = quarterStart.plusMonths(2).with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59);
return new LocalDateTime[]{quarterStart, quarterEnd};
case THIS_YEAR:
LocalDateTime yearStart = now.with(TemporalAdjusters.firstDayOfYear());
LocalDateTime yearEnd = now.with(TemporalAdjusters.lastDayOfYear());
return new LocalDateTime[]{yearStart, yearEnd};
default:
return null;
}
}
private void disposeProductByClassify(List<HardAppProductByClassifyVo> list) {
if (ObjectUtil.isEmpty(list)) return;
// 处理分类
List<Long> classifyIdList = list.stream().map(HardAppProductByClassifyVo::getClassifyId).filter(ObjectUtil::isNotEmpty).distinct().toList();
if (ObjectUtil.isNotEmpty(classifyIdList)) {
List<CanteenCategoryEntity> categoryList = canteenCategoryService.getAllSimple(null, null).getData();
if (ObjectUtil.isNotEmpty(categoryList)) {
Map<Long, CanteenCategoryEntity> categoryMap = categoryList.stream().collect(Collectors.toMap(CanteenCategoryEntity::getId, v -> v));
if (ObjectUtil.isNotEmpty(categoryMap)) {
for (HardAppProductByClassifyVo i : list) {
CanteenCategoryEntity category = categoryMap.get(i.getClassifyId());
if (ObjectUtil.isNotEmpty(category)) {
i.setClassifyName(category.getName());
}
}
}
}
}
}
private void disposeProductByCanteen(List<HardAppProductByCanteenVo> list) {
if (ObjectUtil.isEmpty(list)) return;
// 处理商户
List<Long> canteenIdList = list.stream().map(HardAppProductByCanteenVo::getCanteenId).toList();
if (ObjectUtil.isNotEmpty(canteenIdList)) {
List<MchManageVo> mchList = remoteMchService.getByIds(canteenIdList).getData();
if (ObjectUtil.isNotEmpty(mchList)) {
Map<Long, MchManageVo> categoryMap = mchList.stream().collect(Collectors.toMap(MchManageVo::getId, v -> v));
for (HardAppProductByCanteenVo i : list) {
MchManageVo category = categoryMap.get(i.getCanteenId());
if (ObjectUtil.isNotEmpty(category)) {
i.setCanteenName(category.getName());
}
}
}
}
}
}
@@ -1078,7 +1078,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
}
}
// 部门
List<Long> deptIds = list.stream().map(HardOrderVo::getDeptId).filter(ObjectUtil::isNotEmpty).distinct().toList();
List<Long> deptIds = list.stream().map(HardOrderVo::getUserDeptId).filter(ObjectUtil::isNotEmpty).distinct().toList();
if (ObjectUtil.isNotEmpty(deptIds)) {
R<Map<Long, SysDept>> deptList = deptService.getDeptByDeptIds(deptIds);
if (ObjectUtil.isNotEmpty(deptList.getData())) {
@@ -286,4 +286,67 @@
order by o.user_dept_id, o.hour_type
</select>
<select id="productByClassify" resultType="com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByClassifyVo">
select s.category_id as classifyId,
SUM(a.product_count) as payCount,
SUM(a.total_price) as totalPrice,
count(distinct o.id) as timeCount,
count(distinct o.user_id) as payUserCount
from pjcloudx_hardware.hard_car a
inner join pjcloudx_hardware.hard_parent_car p on a.parent_car_id = p.id and p.del_flag = '0'
inner join pjcloudx_hardware.hard_order o
on o.parent_car_id = p.id and o.del_flag = '0' and o.hour_type is not null and
o.hour_type not in ('-1')
left join pjcloudx_canteen.canteen_spu s on a.product_id = s.id
<where>
a.del_flag = '0'
<if test="dto.hourType != null and dto.hourType != '' ">
and o.hour_type = #{dto.hourType}
</if>
<if test="dto.canteenIdList != null and dto.canteenIdList.size() != 0">
and o.merchant_id in
<foreach collection="dto.canteenIdList" item="v" open="(" close=")" separator=",">
#{v}
</foreach>
</if>
<if test="dto.payTimeList != null and dto.payTimeList.length == 2">
and o.pay_time between #{dto.payTimeList[0]} and #{dto.payTimeList[1]}
</if>
</where>
group by s.category_id
order by s.category_id
</select>
<select id="productByCanteen" resultType="com.bsd.pjcloud.hard.api.vo.order.app.HardAppProductByCanteenVo">
select DATE_FORMAT(o.pay_time, '%Y-%m-%d') as time,
o.merchant_id as canteenId,
SUM(a.product_count) as payCount,
SUM(a.total_price) as totalPrice,
count(distinct o.id) as timeCount,
count(distinct o.user_id) as payUserCount
from pjcloudx_hardware.hard_car a
inner join hard_parent_car p on a.parent_car_id = p.id and p.del_flag = '0'
inner join hard_order o
on o.parent_car_id = p.id and o.del_flag = '0' and o.hour_type is not null and
o.hour_type not in ('-1')
<where>
a.del_flag = '0'
and o.pay_time is not null
<if test="dto.canteenIdList != null and dto.canteenIdList.size() != 0">
and o.merchant_id in
<foreach collection="dto.canteenIdList" item="v" open="(" close=")" separator=",">
#{v}
</foreach>
</if>
<if test="dto.hourType != null and dto.hourType != '' ">
and o.hour_type = #{dto.hourType}
</if>
<if test="dto.payTimeList != null and dto.payTimeList.length == 2">
and o.pay_time between #{dto.payTimeList[0]} and #{dto.payTimeList[1]}
</if>
</where>
group by DATE_FORMAT(o.pay_time, '%Y-%m-%d'), o.merchant_id
order by DATE_FORMAT(o.pay_time, '%Y-%m-%d')
</select>
</mapper>