jiaxing.zhou

Merge branch 'dev'

# Conflicts:
#	frontend/components.d.ts
1 +package com.apple.erp.dto.request;
2 +
3 +import lombok.Data;
4 +
5 +import javax.validation.constraints.*;
6 +import java.math.BigDecimal;
7 +
8 +/**
9 + * 返利新增请求DTO
10 + *
11 + * @author Apple ERP
12 + */
13 +@Data
14 +public class RebateAddReq {
15 +
16 + /**
17 + * 返利明细编号
18 + */
19 + @Size(max = 30, message = "返利明细编号不能超过30个字符")
20 + private String rebateNo;
21 +
22 + /**
23 + * 关联订单编号
24 + */
25 + @NotBlank(message = "关联订单编号不能为空")
26 + @Size(max = 30, message = "订单编号不能超过30个字符")
27 + private String orderNo;
28 +
29 + /**
30 + * 经销商编码
31 + */
32 + @NotBlank(message = "经销商编码不能为空")
33 + @Size(max = 20, message = "经销商编码不能超过20个字符")
34 + private String dealerCode;
35 +
36 + /**
37 + * 经销商名称
38 + */
39 + @NotBlank(message = "经销商名称不能为空")
40 + @Size(max = 100, message = "经销商名称不能超过100个字符")
41 + private String dealerName;
42 +
43 + /**
44 + * 产品编码
45 + */
46 + @NotBlank(message = "产品编码不能为空")
47 + @Size(max = 30, message = "产品编码不能超过30个字符")
48 + private String productCode;
49 +
50 + /**
51 + * 返利金额
52 + */
53 + @NotNull(message = "返利金额不能为空")
54 + @DecimalMin(value = "0", message = "返利金额不能小于0")
55 + private BigDecimal rebateAmount;
56 +
57 + /**
58 + * 返利记录日期
59 + */
60 + @NotBlank(message = "返利记录日期不能为空")
61 + private String rebateDate;
62 +
63 + /**
64 + * 操作类型:1-新增,2-扣减
65 + */
66 + @NotNull(message = "操作类型不能为空")
67 + @Min(value = 1, message = "操作类型值无效")
68 + @Max(value = 2, message = "操作类型值无效")
69 + private Integer operateType;
70 +
71 + /**
72 + * 返利计算状态:0-未计算,1-已计算
73 + */
74 + private Integer calcFlag;
75 +}
1 +package com.apple.erp.dto.request;
2 +
3 +import lombok.Data;
4 +
5 +/**
6 + * 返利台账明细查询请求DTO
7 + *
8 + * @author Apple ERP Team
9 + * @version 1.0.0
10 + * @since 2024-01-01
11 + */
12 +@Data
13 +public class RebateQueryReq {
14 +
15 + /**
16 + * 返利明细编号
17 + */
18 + private String rebateNo;
19 +
20 + /**
21 + * 关联订单编号
22 + */
23 + private String orderNo;
24 +
25 + /**
26 + * 经销商编码
27 + */
28 + private String dealerCode;
29 +
30 + /**
31 + * 经销商名称
32 + */
33 + private String dealerName;
34 +
35 + /**
36 + * 产品编码
37 + */
38 + private String productCode;
39 +
40 + /**
41 + * 操作类型:1-新增,2-扣减
42 + */
43 + private Integer operateType;
44 +
45 + /**
46 + * 返利计算状态:0-未计算,1-已计算
47 + */
48 + private Integer calcFlag;
49 +
50 + /**
51 + * 返利记录开始日期
52 + */
53 + private String rebateStartDate;
54 +
55 + /**
56 + * 返利记录结束日期
57 + */
58 + private String rebateEndDate;
59 +
60 + /**
61 + * 页码
62 + */
63 + private Integer pageNum = 1;
64 +
65 + /**
66 + * 页面大小
67 + */
68 + private Integer pageSize = 10;
69 +}
1 +package com.apple.erp.dto.request;
2 +
3 +import lombok.Data;
4 +
5 +import javax.validation.constraints.*;
6 +import java.math.BigDecimal;
7 +
8 +/**
9 + * 返利更新请求DTO
10 + *
11 + * @author Apple ERP
12 + */
13 +@Data
14 +public class RebateUpdateReq {
15 +
16 + /**
17 + * 返利明细ID
18 + */
19 + @NotNull(message = "返利明细ID不能为空")
20 + private Long rebateId;
21 +
22 + /**
23 + * 返利明细编号
24 + */
25 + @Size(max = 30, message = "返利明细编号不能超过30个字符")
26 + private String rebateNo;
27 +
28 + /**
29 + * 关联订单编号
30 + */
31 + @NotBlank(message = "关联订单编号不能为空")
32 + @Size(max = 30, message = "订单编号不能超过30个字符")
33 + private String orderNo;
34 +
35 + /**
36 + * 经销商编码
37 + */
38 + @NotBlank(message = "经销商编码不能为空")
39 + @Size(max = 20, message = "经销商编码不能超过20个字符")
40 + private String dealerCode;
41 +
42 + /**
43 + * 经销商名称
44 + */
45 + @NotBlank(message = "经销商名称不能为空")
46 + @Size(max = 100, message = "经销商名称不能超过100个字符")
47 + private String dealerName;
48 +
49 + /**
50 + * 产品编码
51 + */
52 + @NotBlank(message = "产品编码不能为空")
53 + @Size(max = 30, message = "产品编码不能超过30个字符")
54 + private String productCode;
55 +
56 + /**
57 + * 返利金额
58 + */
59 + @NotNull(message = "返利金额不能为空")
60 + @DecimalMin(value = "0", message = "返利金额不能小于0")
61 + private BigDecimal rebateAmount;
62 +
63 + /**
64 + * 返利记录日期
65 + */
66 + @NotBlank(message = "返利记录日期不能为空")
67 + private String rebateDate;
68 +
69 + /**
70 + * 操作类型:1-新增,2-扣减
71 + */
72 + @NotNull(message = "操作类型不能为空")
73 + @Min(value = 1, message = "操作类型值无效")
74 + @Max(value = 2, message = "操作类型值无效")
75 + private Integer operateType;
76 +
77 + /**
78 + * 返利计算状态:0-未计算,1-已计算
79 + */
80 + private Integer calcFlag;
81 +}
1 +package com.apple.erp.dto.response;
2 +
3 +import lombok.Data;
4 +
5 +import java.math.BigDecimal;
6 +import java.time.LocalDate;
7 +import java.time.LocalDateTime;
8 +
9 +/**
10 + * 返利响应DTO
11 + *
12 + * @author Apple ERP
13 + */
14 +@Data
15 +public class RebateRes {
16 +
17 + /**
18 + * 返利明细ID
19 + */
20 + private Long rebateId;
21 +
22 + /**
23 + * 返利明细编号
24 + */
25 + private String rebateNo;
26 +
27 + /**
28 + * 关联订单编号
29 + */
30 + private String orderNo;
31 +
32 + /**
33 + * 经销商编码
34 + */
35 + private String dealerCode;
36 +
37 + /**
38 + * 经销商名称
39 + */
40 + private String dealerName;
41 +
42 + /**
43 + * 产品编码
44 + */
45 + private String productCode;
46 +
47 + /**
48 + * 返利金额
49 + */
50 + private BigDecimal rebateAmount;
51 +
52 + /**
53 + * 返利记录日期
54 + */
55 + private LocalDate rebateDate;
56 +
57 + /**
58 + * 操作类型:1-新增,2-扣减
59 + */
60 + private Integer operateType;
61 +
62 + /**
63 + * 操作类型文本
64 + */
65 + private String operateTypeText;
66 +
67 + /**
68 + * 返利计算状态:0-未计算,1-已计算
69 + */
70 + private Integer calcFlag;
71 +
72 + /**
73 + * 计算状态文本
74 + */
75 + private String calcFlagText;
76 +
77 + /**
78 + * 数据上传时间
79 + */
80 + private LocalDateTime uploadTime;
81 +
82 + /**
83 + * 创建时间
84 + */
85 + private LocalDateTime createTime;
86 +
87 + /**
88 + * 更新时间
89 + */
90 + private LocalDateTime updateTime;
91 +
92 + /**
93 + * 创建者
94 + */
95 + private String createBy;
96 +
97 + /**
98 + * 更新者
99 + */
100 + private String updateBy;
101 +}
1 +package com.apple.erp.entity;
2 +
3 +import com.baomidou.mybatisplus.annotation.*;
4 +import lombok.Data;
5 +import lombok.EqualsAndHashCode;
6 +
7 +import java.math.BigDecimal;
8 +import java.time.LocalDate;
9 +import java.time.LocalDateTime;
10 +
11 +/**
12 + * 返利实体类
13 + *
14 + * @author Apple ERP
15 + */
16 +@Data
17 +@EqualsAndHashCode(callSuper = false)
18 +@TableName("t_rebate_detail")
19 +public class Rebate {
20 +
21 + /**
22 + * 返利明细ID
23 + */
24 + @TableId(value = "rebate_id", type = IdType.AUTO)
25 + private Long rebateId;
26 +
27 + /**
28 + * 返利明细编号
29 + */
30 + @TableField("rebate_no")
31 + private String rebateNo;
32 +
33 + /**
34 + * 关联订单编号
35 + */
36 + @TableField("order_no")
37 + private String orderNo;
38 +
39 + /**
40 + * 经销商编码
41 + */
42 + @TableField("dealer_code")
43 + private String dealerCode;
44 +
45 + /**
46 + * 经销商名称
47 + */
48 + @TableField("dealer_name")
49 + private String dealerName;
50 +
51 + /**
52 + * 产品编码
53 + */
54 + @TableField("product_code")
55 + private String productCode;
56 +
57 + /**
58 + * 返利金额
59 + */
60 + @TableField("rebate_amount")
61 + private BigDecimal rebateAmount;
62 +
63 + /**
64 + * 返利记录日期
65 + */
66 + @TableField("rebate_date")
67 + private LocalDate rebateDate;
68 +
69 + /**
70 + * 操作类型:1-新增,2-扣减
71 + */
72 + @TableField("operate_type")
73 + private Integer operateType;
74 +
75 + /**
76 + * 返利计算状态:0-未计算,1-已计算
77 + */
78 + @TableField("calc_flag")
79 + private Integer calcFlag;
80 +
81 + /**
82 + * 数据上传时间
83 + */
84 + @TableField("upload_time")
85 + private LocalDateTime uploadTime;
86 +
87 + /**
88 + * 创建时间
89 + */
90 + @TableField(value = "create_time", fill = FieldFill.INSERT)
91 + private LocalDateTime createTime;
92 +
93 + /**
94 + * 更新时间
95 + */
96 + @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
97 + private LocalDateTime updateTime;
98 +
99 + /**
100 + * 创建者
101 + */
102 + @TableField(value = "create_by", fill = FieldFill.INSERT)
103 + private String createBy;
104 +
105 + /**
106 + * 更新者
107 + */
108 + @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
109 + private String updateBy;
110 +
111 + /**
112 + * 删除标志:0-存在,2-删除
113 + */
114 + @TableField("del_flag")
115 + @TableLogic(value = "0", delval = "2")
116 + private String delFlag;
117 +}
1 +package com.apple.erp.mapper;
2 +
3 +import com.apple.erp.entity.Rebate;
4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 +import com.baomidou.mybatisplus.core.metadata.IPage;
6 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
7 +import org.apache.ibatis.annotations.Mapper;
8 +import org.apache.ibatis.annotations.Param;
9 +
10 +import java.math.BigDecimal;
11 +import java.util.List;
12 +import java.util.Map;
13 +
14 +/**
15 + * 返利台账明细Mapper接口
16 + *
17 + * @author Apple ERP Team
18 + * @version 1.0.0
19 + * @since 2024-01-01
20 + */
21 +@Mapper
22 +public interface RebateMapper extends BaseMapper<Rebate> {
23 +
24 + /**
25 + * 分页查询返利明细列表
26 + *
27 + * @param page 分页参数
28 + * @param params 查询参数
29 + * @return 返利明细分页列表
30 + */
31 + IPage<Rebate> selectRebatePage(Page<Rebate> page, @Param("params") Map<String, Object> params);
32 +
33 + /**
34 + * 根据经销商编码统计返利总金额
35 + *
36 + * @param dealerCode 经销商编码
37 + * @param operateType 操作类型
38 + * @return 返利总金额
39 + */
40 + BigDecimal sumRebateAmountByDealer(@Param("dealerCode") String dealerCode, @Param("operateType") Integer operateType);
41 +
42 + /**
43 + * 根据产品编码统计返利总金额
44 + *
45 + * @param productCode 产品编码
46 + * @param operateType 操作类型
47 + * @return 返利总金额
48 + */
49 + BigDecimal sumRebateAmountByProduct(@Param("productCode") String productCode, @Param("operateType") Integer operateType);
50 +
51 + /**
52 + * 统计各操作类型的返利数量
53 + *
54 + * @return 操作类型统计
55 + */
56 + List<Map<String, Object>> countRebateByOperateType();
57 +
58 + /**
59 + * 查询未计算的返利明细列表
60 + *
61 + * @return 未计算返利明细列表
62 + */
63 + List<Rebate> selectUnCalcRebates();
64 +
65 + /**
66 + * 根据返利编号查询返利明细
67 + *
68 + * @param rebateNo 返利编号
69 + * @return 返利明细信息
70 + */
71 + Rebate selectByRebateNo(@Param("rebateNo") String rebateNo);
72 +
73 + /**
74 + * 获取返利月度统计数据
75 + *
76 + * @param year 年份
77 + * @return 月度统计数据
78 + */
79 + List<Map<String, Object>> getRebateMonthlyStats(@Param("year") Integer year);
80 +
81 + /**
82 + * 获取返利状态统计数据
83 + *
84 + * @return 状态统计数据
85 + */
86 + Map<String, Object> getRebateStatusStats();
87 +
88 + /**
89 + * 获取返利趋势统计数据
90 + *
91 + * @param startDate 开始日期
92 + * @param endDate 结束日期
93 + * @return 趋势统计数据
94 + */
95 + List<Map<String, Object>> getRebateTrendStats(@Param("startDate") String startDate, @Param("endDate") String endDate);
96 +}
1 +package com.apple.erp.service;
2 +
3 +import com.apple.erp.dto.request.RebateAddReq;
4 +import com.apple.erp.dto.request.RebateQueryReq;
5 +import com.apple.erp.dto.request.RebateUpdateReq;
6 +import com.apple.erp.dto.response.RebateRes;
7 +import com.apple.erp.entity.Rebate;
8 +import com.baomidou.mybatisplus.core.metadata.IPage;
9 +import com.baomidou.mybatisplus.extension.service.IService;
10 +
11 +import java.math.BigDecimal;
12 +import java.util.List;
13 +import java.util.Map;
14 +
15 +/**
16 + * 返利台账明细服务接口
17 + *
18 + * @author Apple ERP Team
19 + * @version 1.0.0
20 + * @since 2024-01-01
21 + */
22 +public interface RebateService extends IService<Rebate> {
23 +
24 + /**
25 + * 分页查询返利明细列表
26 + *
27 + * @param queryReq 查询请求
28 + * @return 返利明细分页列表
29 + */
30 + IPage<RebateRes> getRebatePage(RebateQueryReq queryReq);
31 +
32 + /**
33 + * 根据ID查询返利明细详情
34 + *
35 + * @param rebateId 返利明细ID
36 + * @return 返利明细详情
37 + */
38 + RebateRes getRebateById(Long rebateId);
39 +
40 + /**
41 + * 新增返利明细
42 + *
43 + * @param addReq 新增请求
44 + * @return 是否成功
45 + */
46 + boolean addRebate(RebateAddReq addReq);
47 +
48 + /**
49 + * 更新返利明细
50 + *
51 + * @param updateReq 更新请求
52 + * @return 是否成功
53 + */
54 + boolean updateRebate(RebateUpdateReq updateReq);
55 +
56 + /**
57 + * 删除返利明细
58 + *
59 + * @param rebateId 返利明细ID
60 + * @return 是否成功
61 + */
62 + boolean deleteRebate(Long rebateId);
63 +
64 + /**
65 + * 批量删除返利明细
66 + *
67 + * @param rebateIds 返利明细ID列表
68 + * @return 是否成功
69 + */
70 + boolean batchDeleteRebate(List<Long> rebateIds);
71 +
72 + /**
73 + * 根据经销商编码统计返利总金额
74 + *
75 + * @param dealerCode 经销商编码
76 + * @param operateType 操作类型(可选)
77 + * @return 返利总金额
78 + */
79 + BigDecimal sumRebateAmountByDealer(String dealerCode, Integer operateType);
80 +
81 + /**
82 + * 根据产品编码统计返利总金额
83 + *
84 + * @param productCode 产品编码
85 + * @param operateType 操作类型(可选)
86 + * @return 返利总金额
87 + */
88 + BigDecimal sumRebateAmountByProduct(String productCode, Integer operateType);
89 +
90 + /**
91 + * 统计各操作类型的返利数量
92 + *
93 + * @return 操作类型统计
94 + */
95 + List<Map<String, Object>> countRebateByOperateType();
96 +
97 + /**
98 + * 查询未计算的返利明细列表
99 + *
100 + * @return 未计算返利明细列表
101 + */
102 + List<RebateRes> getUnCalcRebates();
103 +
104 + /**
105 + * 根据返利编号查询返利明细
106 + *
107 + * @param rebateNo 返利编号
108 + * @return 返利明细信息
109 + */
110 + RebateRes getRebateByNo(String rebateNo);
111 +
112 + /**
113 + * 生成返利编号
114 + *
115 + * @return 返利编号
116 + */
117 + String generateRebateNo();
118 +
119 + /**
120 + * 获取返利月度统计数据
121 + *
122 + * @param year 年份
123 + * @return 月度统计数据
124 + */
125 + List<Map<String, Object>> getRebateMonthlyStats(Integer year);
126 +
127 + /**
128 + * 获取返利状态统计数据
129 + *
130 + * @return 状态统计数据
131 + */
132 + Map<String, Object> getRebateStatusStats();
133 +
134 + /**
135 + * 获取返利趋势统计数据
136 + *
137 + * @param startDate 开始日期
138 + * @param endDate 结束日期
139 + * @return 趋势统计数据
140 + */
141 + List<Map<String, Object>> getRebateTrendStats(String startDate, String endDate);
142 +}
1 +package com.apple.erp.service.impl;
2 +
3 +import com.apple.erp.dto.request.RebateAddReq;
4 +import com.apple.erp.dto.request.RebateQueryReq;
5 +import com.apple.erp.dto.request.RebateUpdateReq;
6 +import com.apple.erp.dto.response.RebateRes;
7 +import com.apple.erp.entity.Rebate;
8 +import com.apple.erp.mapper.RebateMapper;
9 +import com.apple.erp.service.RebateService;
10 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
11 +import com.baomidou.mybatisplus.core.metadata.IPage;
12 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
13 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
14 +import lombok.extern.slf4j.Slf4j;
15 +import org.springframework.beans.BeanUtils;
16 +import org.springframework.beans.factory.annotation.Autowired;
17 +import org.springframework.stereotype.Service;
18 +import org.springframework.transaction.annotation.Transactional;
19 +
20 +import java.math.BigDecimal;
21 +import java.time.LocalDate;
22 +import java.time.LocalDateTime;
23 +import java.time.format.DateTimeFormatter;
24 +import java.util.*;
25 +import java.util.stream.Collectors;
26 +
27 +/**
28 + * 返利台账明细服务实现类
29 + *
30 + * @author Apple ERP Team
31 + * @version 1.0.0
32 + * @since 2024-01-01
33 + */
34 +@Slf4j
35 +@Service
36 +public class RebateServiceImpl extends ServiceImpl<RebateMapper, Rebate> implements RebateService {
37 +
38 + @Autowired
39 + private RebateMapper rebateMapper;
40 +
41 + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
42 +
43 + @Override
44 + public IPage<RebateRes> getRebatePage(RebateQueryReq queryReq) {
45 + // 构建查询参数
46 + Map<String, Object> params = buildQueryParams(queryReq);
47 +
48 + // 创建分页对象
49 + Page<Rebate> page = new Page<>(queryReq.getPageNum(), queryReq.getPageSize());
50 +
51 + // 分页查询
52 + IPage<Rebate> rebatePage = rebateMapper.selectRebatePage(page, params);
53 +
54 + // 转换为响应DTO
55 + Page<RebateRes> resultPage = new Page<>(rebatePage.getCurrent(), rebatePage.getSize(), rebatePage.getTotal());
56 + List<RebateRes> rebateResList = rebatePage.getRecords().stream()
57 + .map(this::convertToRebateRes)
58 + .collect(Collectors.toList());
59 + resultPage.setRecords(rebateResList);
60 +
61 + return resultPage;
62 + }
63 +
64 + @Override
65 + public RebateRes getRebateById(Long rebateId) {
66 + Rebate rebate = getById(rebateId);
67 + return rebate != null ? convertToRebateRes(rebate) : null;
68 + }
69 +
70 + @Override
71 + @Transactional(rollbackFor = Exception.class)
72 + public boolean addRebate(RebateAddReq addReq) {
73 + Rebate rebate = new Rebate();
74 + BeanUtils.copyProperties(addReq, rebate);
75 +
76 + // 设置返利编号(如果未提供)
77 + if (addReq.getRebateNo() == null || addReq.getRebateNo().isEmpty()) {
78 + rebate.setRebateNo(generateRebateNo());
79 + }
80 +
81 + // 转换日期字符串
82 + if (addReq.getRebateDate() != null && !addReq.getRebateDate().isEmpty()) {
83 + rebate.setRebateDate(LocalDate.parse(addReq.getRebateDate(), DATE_FORMATTER));
84 + }
85 +
86 + // 设置上传时间
87 + rebate.setUploadTime(LocalDateTime.now());
88 +
89 + // 默认计算状态为未计算
90 + if (rebate.getCalcFlag() == null) {
91 + rebate.setCalcFlag(0);
92 + }
93 +
94 + return save(rebate);
95 + }
96 +
97 + @Override
98 + @Transactional(rollbackFor = Exception.class)
99 + public boolean updateRebate(RebateUpdateReq updateReq) {
100 + Rebate rebate = getById(updateReq.getRebateId());
101 + if (rebate == null) {
102 + throw new RuntimeException("返利记录不存在");
103 + }
104 +
105 + BeanUtils.copyProperties(updateReq, rebate);
106 +
107 + // 转换日期字符串
108 + if (updateReq.getRebateDate() != null && !updateReq.getRebateDate().isEmpty()) {
109 + rebate.setRebateDate(LocalDate.parse(updateReq.getRebateDate(), DATE_FORMATTER));
110 + }
111 +
112 + return updateById(rebate);
113 + }
114 +
115 + @Override
116 + @Transactional(rollbackFor = Exception.class)
117 + public boolean deleteRebate(Long rebateId) {
118 + return removeById(rebateId);
119 + }
120 +
121 + @Override
122 + @Transactional(rollbackFor = Exception.class)
123 + public boolean batchDeleteRebate(List<Long> rebateIds) {
124 + return removeByIds(rebateIds);
125 + }
126 +
127 + @Override
128 + public BigDecimal sumRebateAmountByDealer(String dealerCode, Integer operateType) {
129 + BigDecimal amount = rebateMapper.sumRebateAmountByDealer(dealerCode, operateType);
130 + return amount != null ? amount : BigDecimal.ZERO;
131 + }
132 +
133 + @Override
134 + public BigDecimal sumRebateAmountByProduct(String productCode, Integer operateType) {
135 + BigDecimal amount = rebateMapper.sumRebateAmountByProduct(productCode, operateType);
136 + return amount != null ? amount : BigDecimal.ZERO;
137 + }
138 +
139 + @Override
140 + public List<Map<String, Object>> countRebateByOperateType() {
141 + return rebateMapper.countRebateByOperateType();
142 + }
143 +
144 + @Override
145 + public List<RebateRes> getUnCalcRebates() {
146 + List<Rebate> rebates = rebateMapper.selectUnCalcRebates();
147 + return rebates.stream()
148 + .map(this::convertToRebateRes)
149 + .collect(Collectors.toList());
150 + }
151 +
152 + @Override
153 + public RebateRes getRebateByNo(String rebateNo) {
154 + Rebate rebate = rebateMapper.selectByRebateNo(rebateNo);
155 + return rebate != null ? convertToRebateRes(rebate) : null;
156 + }
157 +
158 + @Override
159 + public String generateRebateNo() {
160 + String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
161 + String prefix = "RB" + dateStr;
162 +
163 + // 查询当天已有的返利编号数量
164 + LambdaQueryWrapper<Rebate> wrapper = new LambdaQueryWrapper<>();
165 + wrapper.likeRight(Rebate::getRebateNo, prefix);
166 + long count = count(wrapper);
167 +
168 + // 生成4位序号
169 + String sequence = String.format("%04d", count + 1);
170 +
171 + return prefix + sequence;
172 + }
173 +
174 + /**
175 + * 构建查询参数
176 + */
177 + private Map<String, Object> buildQueryParams(RebateQueryReq queryReq) {
178 + Map<String, Object> params = new HashMap<>();
179 +
180 + if (queryReq.getRebateNo() != null && !queryReq.getRebateNo().isEmpty()) {
181 + params.put("rebateNo", queryReq.getRebateNo());
182 + }
183 + if (queryReq.getOrderNo() != null && !queryReq.getOrderNo().isEmpty()) {
184 + params.put("orderNo", queryReq.getOrderNo());
185 + }
186 + if (queryReq.getDealerCode() != null && !queryReq.getDealerCode().isEmpty()) {
187 + params.put("dealerCode", queryReq.getDealerCode());
188 + }
189 + if (queryReq.getDealerName() != null && !queryReq.getDealerName().isEmpty()) {
190 + params.put("dealerName", queryReq.getDealerName());
191 + }
192 + if (queryReq.getProductCode() != null && !queryReq.getProductCode().isEmpty()) {
193 + params.put("productCode", queryReq.getProductCode());
194 + }
195 + if (queryReq.getOperateType() != null) {
196 + params.put("operateType", queryReq.getOperateType());
197 + }
198 + if (queryReq.getCalcFlag() != null) {
199 + params.put("calcFlag", queryReq.getCalcFlag());
200 + }
201 + if (queryReq.getRebateStartDate() != null && !queryReq.getRebateStartDate().isEmpty()) {
202 + params.put("rebateStartDate", queryReq.getRebateStartDate());
203 + }
204 + if (queryReq.getRebateEndDate() != null && !queryReq.getRebateEndDate().isEmpty()) {
205 + params.put("rebateEndDate", queryReq.getRebateEndDate());
206 + }
207 +
208 + return params;
209 + }
210 +
211 + /**
212 + * 转换为响应DTO
213 + */
214 + private RebateRes convertToRebateRes(Rebate rebate) {
215 + RebateRes rebateRes = new RebateRes();
216 + BeanUtils.copyProperties(rebate, rebateRes);
217 +
218 + // 设置操作类型文本
219 + rebateRes.setOperateTypeText(getOperateTypeText(rebate.getOperateType()));
220 +
221 + // 设置计算状态文本
222 + rebateRes.setCalcFlagText(getCalcFlagText(rebate.getCalcFlag()));
223 +
224 + return rebateRes;
225 + }
226 +
227 + /**
228 + * 获取操作类型文本
229 + */
230 + private String getOperateTypeText(Integer operateType) {
231 + if (operateType == null) {
232 + return "";
233 + }
234 + switch (operateType) {
235 + case 1:
236 + return "新增";
237 + case 2:
238 + return "扣减";
239 + default:
240 + return "未知";
241 + }
242 + }
243 +
244 + /**
245 + * 获取计算状态文本
246 + */
247 + private String getCalcFlagText(Integer calcFlag) {
248 + if (calcFlag == null) {
249 + return "";
250 + }
251 + switch (calcFlag) {
252 + case 0:
253 + return "未计算";
254 + case 1:
255 + return "已计算";
256 + default:
257 + return "未知";
258 + }
259 + }
260 +
261 + @Override
262 + public List<Map<String, Object>> getRebateMonthlyStats(Integer year) {
263 + log.info("获取返利月度统计数据,年份:{}", year);
264 + return rebateMapper.getRebateMonthlyStats(year);
265 + }
266 +
267 + @Override
268 + public Map<String, Object> getRebateStatusStats() {
269 + log.info("获取返利状态统计数据");
270 + return rebateMapper.getRebateStatusStats();
271 + }
272 +
273 + @Override
274 + public List<Map<String, Object>> getRebateTrendStats(String startDate, String endDate) {
275 + log.info("获取返利趋势统计数据,开始日期:{},结束日期:{}", startDate, endDate);
276 + return rebateMapper.getRebateTrendStats(startDate, endDate);
277 + }
278 +}
...@@ -17,8 +17,8 @@ spring: ...@@ -17,8 +17,8 @@ spring:
17 type: com.alibaba.druid.pool.DruidDataSource 17 type: com.alibaba.druid.pool.DruidDataSource
18 driver-class-name: com.mysql.cj.jdbc.Driver 18 driver-class-name: com.mysql.cj.jdbc.Driver
19 url: jdbc:mysql://localhost:3306/apple_erp?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true 19 url: jdbc:mysql://localhost:3306/apple_erp?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
20 - username: root 20 + username: apple_erp_app
21 - password: MySQL@123 21 + password: StrongPassw0rd!
22 druid: 22 druid:
23 # 初始连接数 23 # 初始连接数
24 initial-size: 5 24 initial-size: 5
...@@ -70,7 +70,7 @@ spring: ...@@ -70,7 +70,7 @@ spring:
70 redis: 70 redis:
71 host: localhost 71 host: localhost
72 port: 6379 72 port: 6379
73 - password: 73 + password: 123456
74 database: 0 74 database: 0
75 timeout: 10000ms 75 timeout: 10000ms
76 lettuce: 76 lettuce:
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 +<mapper namespace="com.apple.erp.mapper.RebateMapper">
4 +
5 + <!-- 返利明细基础字段 -->
6 + <sql id="baseColumns">
7 + rebate_id, rebate_no, order_no, dealer_code, dealer_name, product_code,
8 + rebate_amount, rebate_date, operate_type, calc_flag, upload_time,
9 + create_by, create_time, update_by, update_time
10 + </sql>
11 +
12 + <!-- 分页查询返利明细列表 -->
13 + <select id="selectRebatePage" resultType="com.apple.erp.entity.Rebate">
14 + SELECT
15 + <include refid="baseColumns"/>
16 + FROM t_rebate_detail
17 + WHERE del_flag = '0'
18 + <if test="params.rebateNo != null and params.rebateNo != ''">
19 + AND rebate_no LIKE CONCAT('%', #{params.rebateNo}, '%')
20 + </if>
21 + <if test="params.orderNo != null and params.orderNo != ''">
22 + AND order_no LIKE CONCAT('%', #{params.orderNo}, '%')
23 + </if>
24 + <if test="params.dealerCode != null and params.dealerCode != ''">
25 + AND dealer_code = #{params.dealerCode}
26 + </if>
27 + <if test="params.dealerName != null and params.dealerName != ''">
28 + AND dealer_name LIKE CONCAT('%', #{params.dealerName}, '%')
29 + </if>
30 + <if test="params.productCode != null and params.productCode != ''">
31 + AND product_code = #{params.productCode}
32 + </if>
33 + <if test="params.operateType != null">
34 + AND operate_type = #{params.operateType}
35 + </if>
36 + <if test="params.calcFlag != null">
37 + AND calc_flag = #{params.calcFlag}
38 + </if>
39 + <if test="params.rebateStartDate != null and params.rebateStartDate != ''">
40 + AND rebate_date &gt;= #{params.rebateStartDate}
41 + </if>
42 + <if test="params.rebateEndDate != null and params.rebateEndDate != ''">
43 + AND rebate_date &lt;= #{params.rebateEndDate}
44 + </if>
45 + ORDER BY create_time DESC
46 + </select>
47 +
48 + <!-- 根据经销商编码统计返利总金额 -->
49 + <select id="sumRebateAmountByDealer" resultType="java.math.BigDecimal">
50 + SELECT COALESCE(SUM(rebate_amount), 0)
51 + FROM t_rebate_detail
52 + WHERE del_flag = '0'
53 + AND dealer_code = #{dealerCode}
54 + <if test="operateType != null">
55 + AND operate_type = #{operateType}
56 + </if>
57 + </select>
58 +
59 + <!-- 根据产品编码统计返利总金额 -->
60 + <select id="sumRebateAmountByProduct" resultType="java.math.BigDecimal">
61 + SELECT COALESCE(SUM(rebate_amount), 0)
62 + FROM t_rebate_detail
63 + WHERE del_flag = '0'
64 + AND product_code = #{productCode}
65 + <if test="operateType != null">
66 + AND operate_type = #{operateType}
67 + </if>
68 + </select>
69 +
70 + <!-- 统计各操作类型的返利数量 -->
71 + <select id="countRebateByOperateType" resultType="java.util.Map">
72 + SELECT
73 + operate_type,
74 + COUNT(*) as count,
75 + COALESCE(SUM(rebate_amount), 0) as totalAmount
76 + FROM t_rebate_detail
77 + WHERE del_flag = '0'
78 + GROUP BY operate_type
79 + </select>
80 +
81 + <!-- 查询未计算的返利明细列表 -->
82 + <select id="selectUnCalcRebates" resultType="com.apple.erp.entity.Rebate">
83 + SELECT
84 + <include refid="baseColumns"/>
85 + FROM t_rebate_detail
86 + WHERE del_flag = '0'
87 + AND calc_flag = 0
88 + ORDER BY create_time ASC
89 + </select>
90 +
91 + <!-- 根据返利编号查询返利明细 -->
92 + <select id="selectByRebateNo" resultType="com.apple.erp.entity.Rebate">
93 + SELECT
94 + <include refid="baseColumns"/>
95 + FROM t_rebate_detail
96 + WHERE del_flag = '0'
97 + AND rebate_no = #{rebateNo}
98 + </select>
99 +
100 + <!-- 获取返利月度统计数据 -->
101 + <select id="getRebateMonthlyStats" resultType="java.util.Map">
102 + SELECT
103 + MONTH(rebate_date) as month,
104 + COALESCE(SUM(CASE WHEN operate_type = 1 THEN rebate_amount ELSE -rebate_amount END), 0) as totalAmount,
105 + COALESCE(SUM(CASE WHEN calc_flag = 1 AND operate_type = 1 THEN rebate_amount
106 + WHEN calc_flag = 1 AND operate_type = 2 THEN -rebate_amount
107 + ELSE 0 END), 0) as calculatedAmount,
108 + COUNT(*) as totalCount,
109 + COUNT(CASE WHEN calc_flag = 1 THEN 1 END) as calculatedCount
110 + FROM t_rebate_detail
111 + WHERE del_flag = '0'
112 + AND YEAR(rebate_date) = #{year}
113 + GROUP BY MONTH(rebate_date)
114 + ORDER BY month
115 + </select>
116 +
117 + <!-- 获取返利状态统计数据 -->
118 + <select id="getRebateStatusStats" resultType="java.util.Map">
119 + SELECT
120 + COUNT(CASE WHEN calc_flag = 1 THEN 1 END) as calculatedCount,
121 + COUNT(CASE WHEN calc_flag = 0 THEN 1 END) as unCalculatedCount,
122 + COUNT(*) as totalCount,
123 + COALESCE(SUM(CASE WHEN calc_flag = 1 AND operate_type = 1 THEN rebate_amount
124 + WHEN calc_flag = 1 AND operate_type = 2 THEN -rebate_amount
125 + ELSE 0 END), 0) as calculatedAmount,
126 + COALESCE(SUM(CASE WHEN operate_type = 1 THEN rebate_amount ELSE -rebate_amount END), 0) as totalAmount
127 + FROM t_rebate_detail
128 + WHERE del_flag = '0'
129 + </select>
130 +
131 + <!-- 获取返利趋势统计数据 -->
132 + <select id="getRebateTrendStats" resultType="java.util.Map">
133 + SELECT
134 + DATE(rebate_date) as date,
135 + COALESCE(SUM(CASE WHEN operate_type = 1 THEN rebate_amount ELSE -rebate_amount END), 0) as totalAmount,
136 + COALESCE(SUM(CASE WHEN calc_flag = 1 AND operate_type = 1 THEN rebate_amount
137 + WHEN calc_flag = 1 AND operate_type = 2 THEN -rebate_amount
138 + ELSE 0 END), 0) as calculatedAmount,
139 + COUNT(*) as totalCount,
140 + COUNT(CASE WHEN calc_flag = 1 THEN 1 END) as calculatedCount
141 + FROM t_rebate_detail
142 + WHERE del_flag = '0'
143 + <if test="startDate != null and startDate != ''">
144 + AND rebate_date >= #{startDate}
145 + </if>
146 + <if test="endDate != null and endDate != ''">
147 + AND rebate_date &lt;= #{endDate}
148 + </if>
149 + GROUP BY DATE(rebate_date)
150 + ORDER BY date
151 + </select>
152 +
153 +</mapper>
...@@ -51,7 +51,8 @@ ...@@ -51,7 +51,8 @@
51 </select> 51 </select>
52 52
53 <select id="selectMenuTreeByRoleId" parameterType="Long" resultMap="SysMenuResult"> 53 <select id="selectMenuTreeByRoleId" parameterType="Long" resultMap="SysMenuResult">
54 - select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.menu_type, m.status, m.perms, m.icon, m.create_by, m.create_time, m.update_by, m.update_time, m.del_flag 54 + select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.menu_type, m.status, m.perms, m.icon, m.create_by, m.create_time, m.update_by, m.update_time, m.del_flag,
55 + m.sort
55 from t_sys_menu m 56 from t_sys_menu m
56 left join t_sys_role_menu rm on m.menu_id = rm.menu_id 57 left join t_sys_role_menu rm on m.menu_id = rm.menu_id
57 where rm.role_id = #{roleId} and m.status = 1 and m.del_flag = '0' 58 where rm.role_id = #{roleId} and m.status = 1 and m.del_flag = '0'
......
1 +import request from '@/utils/request'
2 +
3 +// 返利台账明细类型定义
4 +export interface Rebate {
5 + rebateId?: number
6 + rebateNo?: string
7 + orderNo: string
8 + dealerCode: string
9 + dealerName: string
10 + productCode: string
11 + rebateAmount: number
12 + rebateDate: string
13 + operateType: number
14 + operateTypeText?: string
15 + calcFlag?: number
16 + calcFlagText?: string
17 + uploadTime?: string
18 + createTime?: string
19 + updateTime?: string
20 + createBy?: string
21 + updateBy?: string
22 +}
23 +
24 +// 返利查询参数
25 +export interface RebateSearchParams {
26 + pageNum: number
27 + pageSize: number
28 + rebateNo?: string
29 + orderNo?: string
30 + dealerCode?: string
31 + dealerName?: string
32 + productCode?: string
33 + operateType?: number
34 + calcFlag?: number
35 + rebateStartDate?: string
36 + rebateEndDate?: string
37 +}
38 +
39 +// 返利新增参数
40 +export interface RebateAddParams {
41 + rebateNo?: string
42 + orderNo: string
43 + dealerCode: string
44 + dealerName: string
45 + productCode: string
46 + rebateAmount: number
47 + rebateDate: string
48 + operateType: number
49 + calcFlag?: number
50 +}
51 +
52 +// 返利更新参数
53 +export interface RebateUpdateParams extends RebateAddParams {
54 + rebateId: number
55 +}
56 +
57 +// 分页查询返利列表
58 +export const getRebatePage = (params: RebateSearchParams) => {
59 + return request({
60 + url: '/api/rebate/page',
61 + method: 'post',
62 + data: params
63 + })
64 +}
65 +
66 +// 根据ID查询返利详情
67 +export const getRebateById = (rebateId: number) => {
68 + return request({
69 + url: `/api/rebate/${rebateId}`,
70 + method: 'get'
71 + })
72 +}
73 +
74 +// 新增返利
75 +export const addRebate = (data: RebateAddParams) => {
76 + return request({
77 + url: '/api/rebate/add',
78 + method: 'post',
79 + data
80 + })
81 +}
82 +
83 +// 更新返利
84 +export const updateRebate = (data: RebateUpdateParams) => {
85 + return request({
86 + url: '/api/rebate/update',
87 + method: 'post',
88 + data
89 + })
90 +}
91 +
92 +// 删除返利
93 +export const deleteRebate = (rebateId: number) => {
94 + return request({
95 + url: `/api/rebate/${rebateId}`,
96 + method: 'delete'
97 + })
98 +}
99 +
100 +// 批量删除返利
101 +export const batchDeleteRebate = (rebateIds: number[]) => {
102 + return request({
103 + url: '/api/rebate/batchDelete',
104 + method: 'post',
105 + data: rebateIds
106 + })
107 +}
108 +
109 +// 标记返利为已计算
110 +export const markRebateCalculated = (rebateId: number) => {
111 + return request({
112 + url: `/api/rebate/markCalculated/${rebateId}`,
113 + method: 'post'
114 + })
115 +}
116 +
117 +// 批量标记返利为已计算
118 +export const batchMarkRebateCalculated = (rebateIds: number[]) => {
119 + return request({
120 + url: '/api/rebate/batchMarkCalculated',
121 + method: 'post',
122 + data: rebateIds
123 + })
124 +}
125 +
126 +// 根据经销商编码统计返利总金额
127 +export const sumRebateAmountByDealer = (dealerCode: string, operateType?: number) => {
128 + return request({
129 + url: `/api/rebate/sumByDealer/${dealerCode}`,
130 + method: 'get',
131 + params: { operateType }
132 + })
133 +}
134 +
135 +// 根据产品编码统计返利总金额
136 +export const sumRebateAmountByProduct = (productCode: string, operateType?: number) => {
137 + return request({
138 + url: `/api/rebate/sumByProduct/${productCode}`,
139 + method: 'get',
140 + params: { operateType }
141 + })
142 +}
143 +
144 +// 统计各操作类型的返利数量
145 +export const countRebateByOperateType = () => {
146 + return request({
147 + url: '/api/rebate/countByOperateType',
148 + method: 'get'
149 + })
150 +}
151 +
152 +// 查询未计算的返利明细列表
153 +export const getUnCalcRebates = () => {
154 + return request({
155 + url: '/api/rebate/unCalc',
156 + method: 'get'
157 + })
158 +}
159 +
160 +// 根据返利编号查询返利
161 +export const getRebateByNo = (rebateNo: string) => {
162 + return request({
163 + url: `/api/rebate/byNo/${rebateNo}`,
164 + method: 'get'
165 + })
166 +}
167 +
168 +// 生成返利编号
169 +export const generateRebateNo = () => {
170 + return request({
171 + url: '/api/rebate/generateNo',
172 + method: 'get'
173 + })
174 +}
175 +
176 +// 导出返利数据
177 +export const exportRebate = (params: RebateSearchParams) => {
178 + return request({
179 + url: '/api/rebate/export',
180 + method: 'post',
181 + data: params,
182 + responseType: 'blob'
183 + })
184 +}
185 +
186 +// 获取返利月度统计数据
187 +export const getRebateMonthlyStats = (year?: number) => {
188 + return request({
189 + url: '/api/rebate/monthlyStats',
190 + method: 'get',
191 + params: { year: year || new Date().getFullYear() }
192 + })
193 +}
194 +
195 +// 获取返利状态统计数据
196 +export const getRebateStatusStats = () => {
197 + return request({
198 + url: '/api/rebate/statusStats',
199 + method: 'get'
200 + })
201 +}
202 +
203 +// 获取返利趋势统计数据
204 +export const getRebateTrendStats = (startDate?: string, endDate?: string) => {
205 + return request({
206 + url: '/api/rebate/trendStats',
207 + method: 'get',
208 + params: { startDate, endDate }
209 + })
210 +}
211 +
212 +export default {
213 + getRebatePage,
214 + getRebateById,
215 + addRebate,
216 + updateRebate,
217 + deleteRebate,
218 + batchDeleteRebate,
219 + markRebateCalculated,
220 + batchMarkRebateCalculated,
221 + sumRebateAmountByDealer,
222 + sumRebateAmountByProduct,
223 + countRebateByOperateType,
224 + getUnCalcRebates,
225 + getRebateByNo,
226 + generateRebateNo,
227 + exportRebate,
228 + getRebateMonthlyStats,
229 + getRebateStatusStats,
230 + getRebateTrendStats
231 +}
...@@ -146,6 +146,7 @@ const menuItems = ref([ ...@@ -146,6 +146,7 @@ const menuItems = ref([
146 { name: '发票管理', path: '/main/invoice', icon: '🧾' }, 146 { name: '发票管理', path: '/main/invoice', icon: '🧾' },
147 { name: '产品管理', path: '/main/product', icon: '📦' }, 147 { name: '产品管理', path: '/main/product', icon: '📦' },
148 { name: '经销商管理', path: '/main/dealer', icon: '🏢' }, 148 { name: '经销商管理', path: '/main/dealer', icon: '🏢' },
149 + { name: '返利管理', path: '/main/rebate', icon: '💰' },
149 { 150 {
150 name: '系统设置', 151 name: '系统设置',
151 icon: '⚙️', 152 icon: '⚙️',
......
...@@ -99,24 +99,6 @@ const staticRoutes: RouteRecordRaw[] = [ ...@@ -99,24 +99,6 @@ const staticRoutes: RouteRecordRaw[] = [
99 } 99 }
100 }, 100 },
101 { 101 {
102 - path: 'dicts',
103 - name: 'Dicts',
104 - component: () => import('@/views/dicts/index.vue'),
105 - meta: {
106 - title: '字典管理',
107 - requiresAuth: true
108 - }
109 - },
110 - {
111 - path: 'logs',
112 - name: 'Logs',
113 - component: () => import('@/views/logs/index.vue'),
114 - meta: {
115 - title: '日志管理',
116 - requiresAuth: true
117 - }
118 - },
119 - {
120 path: 'product', 102 path: 'product',
121 name: 'Product', 103 name: 'Product',
122 component: () => import('@/views/product/index.vue'), 104 component: () => import('@/views/product/index.vue'),
...@@ -162,6 +144,15 @@ const staticRoutes: RouteRecordRaw[] = [ ...@@ -162,6 +144,15 @@ const staticRoutes: RouteRecordRaw[] = [
162 } 144 }
163 }, 145 },
164 { 146 {
147 + path: 'rebate',
148 + name: 'Rebate',
149 + component: () => import('@/views/rebate/index.vue'),
150 + meta: {
151 + title: '返利管理',
152 + requiresAuth: true
153 + }
154 + },
155 + {
165 path: 'settings', 156 path: 'settings',
166 name: 'Settings', 157 name: 'Settings',
167 component: () => import('@/views/settings/index.vue'), 158 component: () => import('@/views/settings/index.vue'),
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.