jiaxing.zhou

feat(frontend): 添加返利管理功能模块

- 新增返利管理页面路由配置
- 实现出库列表页面字段和逻辑调整
- 更新发票管理页面引用类型和方法名
- 添加出库API接口及类型定义
- 主布局菜单增加返利管理入口- 权限管理模块API调用方法更新
- 新建返利管理详情页面组件- 实现返利数据查询、展示和操作功能
- 添加返利统计图表可视化功能
- 完善返利详情查看和编辑流程
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>
...@@ -7,21 +7,30 @@ export {} ...@@ -7,21 +7,30 @@ export {}
7 7
8 declare module 'vue' { 8 declare module 'vue' {
9 export interface GlobalComponents { 9 export interface GlobalComponents {
10 - ActionBar: typeof import('./src/components/common/ActionBar.vue')['default']
11 - DataTable: typeof import('./src/components/common/DataTable.vue')['default']
12 ElButton: typeof import('element-plus/es')['ElButton'] 10 ElButton: typeof import('element-plus/es')['ElButton']
13 - ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] 11 + ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
12 + ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
13 + ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
14 + ElDialog: typeof import('element-plus/es')['ElDialog']
14 ElForm: typeof import('element-plus/es')['ElForm'] 15 ElForm: typeof import('element-plus/es')['ElForm']
15 ElFormItem: typeof import('element-plus/es')['ElFormItem'] 16 ElFormItem: typeof import('element-plus/es')['ElFormItem']
16 ElInput: typeof import('element-plus/es')['ElInput'] 17 ElInput: typeof import('element-plus/es')['ElInput']
17 - ElLink: typeof import('element-plus/es')['ElLink'] 18 + ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
19 + ElOption: typeof import('element-plus/es')['ElOption']
20 + ElPagination: typeof import('element-plus/es')['ElPagination']
21 + ElRadio: typeof import('element-plus/es')['ElRadio']
22 + ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
23 + ElSelect: typeof import('element-plus/es')['ElSelect']
24 + ElTable: typeof import('element-plus/es')['ElTable']
25 + ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
26 + ElTag: typeof import('element-plus/es')['ElTag']
18 Header: typeof import('./src/components/layout/Header.vue')['default'] 27 Header: typeof import('./src/components/layout/Header.vue')['default']
19 - Pagination: typeof import('./src/components/common/Pagination.vue')['default']
20 RouterLink: typeof import('vue-router')['RouterLink'] 28 RouterLink: typeof import('vue-router')['RouterLink']
21 RouterView: typeof import('vue-router')['RouterView'] 29 RouterView: typeof import('vue-router')['RouterView']
22 - SearchBar: typeof import('./src/components/common/SearchBar.vue')['default']
23 Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default'] 30 Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default']
24 SidebarItem: typeof import('./src/components/layout/SidebarItem.vue')['default'] 31 SidebarItem: typeof import('./src/components/layout/SidebarItem.vue')['default']
25 - TableToolbar: typeof import('./src/components/common/TableToolbar.vue')['default'] 32 + }
33 + export interface ComponentCustomProperties {
34 + vLoading: typeof import('element-plus/es')['ElLoadingDirective']
26 } 35 }
27 } 36 }
......
1 +import { request } from '../utils/request'
2 +
3 +// 出库相关类型定义
4 +export interface DeliveryInfo {
5 + deliveryId: number
6 + orderId: number
7 + orderNo: string
8 + dealerCode: string
9 + dealerName: string
10 + deliveryDate: string
11 + totalAmount: number
12 + deliveryStatus: number
13 + createBy?: string
14 + createTime?: string
15 + updateBy?: string
16 + updateTime?: string
17 + deliveryItems?: DeliveryItemInfo[]
18 +}
19 +
20 +export interface DeliveryItemInfo {
21 + itemId?: number
22 + deliveryId?: number
23 + productCode: string
24 + productName: string
25 + productQty: number
26 + unitPrice: number
27 + totalPrice: number
28 + createBy?: string
29 + createTime?: string
30 +}
31 +
32 +export interface DeliveryQueryReq {
33 + pageNum?: number
34 + pageSize?: number
35 + orderNo?: string
36 + dealerCode?: string
37 + dealerName?: string
38 + deliveryStartDate?: string
39 + deliveryEndDate?: string
40 + deliveryStatus?: number
41 +}
42 +
43 +export interface DeliveryAddReq {
44 + orderId: number
45 + deliveryDate: string
46 + deliveryItems: Omit<DeliveryItemInfo, 'itemId' | 'deliveryId' | 'createBy' | 'createTime'>[]
47 +}
48 +
49 +export interface DeliveryUpdateReq {
50 + deliveryId: number
51 + deliveryDate?: string
52 + deliveryStatus?: number
53 + deliveryItems?: Omit<DeliveryItemInfo, 'itemId' | 'deliveryId' | 'createBy' | 'createTime'>[]
54 +}
55 +
56 +// 出库API接口
57 +export const deliveryApi = {
58 + // 分页查询出库列表
59 + getDeliveryList: (params: DeliveryQueryReq) => {
60 + return request.get('/api/delivery/list', { params })
61 + },
62 +
63 + // 获取出库详情
64 + getDeliveryDetail: (deliveryId: number) => {
65 + return request.get(`/api/delivery/${deliveryId}`)
66 + },
67 +
68 + // 新增出库
69 + addDelivery: (data: DeliveryAddReq) => {
70 + return request.post('/api/delivery/add', data)
71 + },
72 +
73 + // 更新出库
74 + updateDelivery: (data: DeliveryUpdateReq) => {
75 + return request.post('/api/delivery/update', data)
76 + },
77 +
78 + // 删除出库
79 + deleteDelivery: (deliveryId: number) => {
80 + return request.delete(`/api/delivery/${deliveryId}`)
81 + },
82 +
83 + // 批量删除出库
84 + batchDeleteDelivery: (deliveryIds: number[]) => {
85 + return request.post('/api/delivery/batchDelete', deliveryIds)
86 + },
87 +
88 + // 导出出库数据
89 + exportDelivery: (params: DeliveryQueryReq) => {
90 + return request.get('/api/delivery/export', { params, responseType: 'blob' })
91 + }
92 +}
93 +
94 +export default deliveryApi
1 +import { request } from '../utils/request'
2 +
3 +// 发票相关类型定义
4 +export interface InvoiceInfo {
5 + invoiceId: number
6 + orderId: number
7 + orderNo: string
8 + dealerCode: string
9 + dealerName: string
10 + invoiceDate: string
11 + totalAmount: number
12 + invoiceStatus: number
13 + invoiceNo?: string
14 + createBy?: string
15 + createTime?: string
16 + updateBy?: string
17 + updateTime?: string
18 + invoiceItems?: InvoiceItemInfo[]
19 +}
20 +
21 +export interface InvoiceItemInfo {
22 + itemId?: number
23 + invoiceId?: number
24 + productCode: string
25 + productName: string
26 + productQty: number
27 + unitPrice: number
28 + totalPrice: number
29 + createBy?: string
30 + createTime?: string
31 +}
32 +
33 +export interface InvoiceQueryReq {
34 + pageNum?: number
35 + pageSize?: number
36 + orderNo?: string
37 + dealerCode?: string
38 + dealerName?: string
39 + invoiceStartDate?: string
40 + invoiceEndDate?: string
41 + invoiceStatus?: number
42 +}
43 +
44 +export interface InvoiceAddReq {
45 + orderId: number
46 + invoiceDate: string
47 + invoiceNo?: string
48 + invoiceItems: Omit<InvoiceItemInfo, 'itemId' | 'invoiceId' | 'createBy' | 'createTime'>[]
49 +}
50 +
51 +export interface InvoiceUpdateReq {
52 + invoiceId: number
53 + invoiceDate?: string
54 + invoiceStatus?: number
55 + invoiceNo?: string
56 + invoiceItems?: Omit<InvoiceItemInfo, 'itemId' | 'invoiceId' | 'createBy' | 'createTime'>[]
57 +}
58 +
59 +// 发票API接口
60 +export const invoiceApi = {
61 + // 分页查询发票列表
62 + getInvoiceList: (params: InvoiceQueryReq) => {
63 + return request.get('/api/invoice/list', { params })
64 + },
65 +
66 + // 获取发票详情
67 + getInvoiceDetail: (invoiceId: number) => {
68 + return request.get(`/api/invoice/${invoiceId}`)
69 + },
70 +
71 + // 新增发票
72 + addInvoice: (data: InvoiceAddReq) => {
73 + return request.post('/api/invoice/add', data)
74 + },
75 +
76 + // 更新发票
77 + updateInvoice: (data: InvoiceUpdateReq) => {
78 + return request.post('/api/invoice/update', data)
79 + },
80 +
81 + // 删除发票
82 + deleteInvoice: (invoiceId: number) => {
83 + return request.delete(`/api/invoice/${invoiceId}`)
84 + },
85 +
86 + // 批量删除发票
87 + batchDeleteInvoice: (invoiceIds: number[]) => {
88 + return request.post('/api/invoice/batchDelete', invoiceIds)
89 + },
90 +
91 + // 导出发票数据
92 + exportInvoice: (params: InvoiceQueryReq) => {
93 + return request.get('/api/invoice/export', { params, responseType: 'blob' })
94 + }
95 +}
96 +
97 +export default invoiceApi
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: '⚙️',
......
...@@ -144,6 +144,15 @@ const staticRoutes: RouteRecordRaw[] = [ ...@@ -144,6 +144,15 @@ const staticRoutes: RouteRecordRaw[] = [
144 } 144 }
145 }, 145 },
146 { 146 {
147 + path: 'rebate',
148 + name: 'Rebate',
149 + component: () => import('@/views/rebate/index.vue'),
150 + meta: {
151 + title: '返利管理',
152 + requiresAuth: true
153 + }
154 + },
155 + {
147 path: 'settings', 156 path: 'settings',
148 name: 'Settings', 157 name: 'Settings',
149 component: () => import('@/views/settings/index.vue'), 158 component: () => import('@/views/settings/index.vue'),
......
1 import { defineStore } from 'pinia' 1 import { defineStore } from 'pinia'
2 import { ref } from 'vue' 2 import { ref } from 'vue'
3 import type { Menu, RouteRecord } from '@/types' 3 import type { Menu, RouteRecord } from '@/types'
4 -import { menuApi } from '@/api/menu' 4 +import { getMenuListApi } from '@/api/menu'
5 import { useUserStore } from './user' 5 import { useUserStore } from './user'
6 import router from '@/router' 6 import router from '@/router'
7 7
...@@ -18,7 +18,7 @@ export const usePermissionStore = defineStore('permission', () => { ...@@ -18,7 +18,7 @@ export const usePermissionStore = defineStore('permission', () => {
18 // 获取菜单列表 18 // 获取菜单列表
19 const getMenuList = async (): Promise<Menu[]> => { 19 const getMenuList = async (): Promise<Menu[]> => {
20 try { 20 try {
21 - const response = await menuApi.getMenuTree() 21 + const response: Menu[] = await getMenuListApi()
22 menuList.value = response 22 menuList.value = response
23 return response 23 return response
24 } catch (error) { 24 } catch (error) {
......
...@@ -86,33 +86,33 @@ ...@@ -86,33 +86,33 @@
86 <table class="data-table"> 86 <table class="data-table">
87 <thead> 87 <thead>
88 <tr> 88 <tr>
89 - <th>订单ID</th> 89 + <th>出库ID</th>
90 - <th class="sortable">订单编号 ↕️</th> 90 + <th class="sortable">出库单号 ↕️</th>
91 <th>经销商编码</th> 91 <th>经销商编码</th>
92 <th>经销商名称</th> 92 <th>经销商名称</th>
93 - <th>订单日期</th> 93 + <th>出库日期</th>
94 - <th>订单金额</th> 94 + <th>出库金额</th>
95 <th>出库状态</th> 95 <th>出库状态</th>
96 - <th>出库时间</th> 96 + <th>创建时间</th>
97 <th>操作</th> 97 <th>操作</th>
98 </tr> 98 </tr>
99 </thead> 99 </thead>
100 <tbody> 100 <tbody>
101 - <tr v-for="order in orderList" :key="order.orderId"> 101 + <tr v-for="delivery in deliveryList" :key="delivery.deliveryId">
102 - <td>{{ order.orderId }}</td> 102 + <td>{{ delivery.deliveryId }}</td>
103 - <td>{{ order.orderNo }}</td> 103 + <td>{{ delivery.deliveryNo }}</td>
104 - <td>{{ order.dealerCode }}</td> 104 + <td>{{ delivery.dealerCode }}</td>
105 - <td>{{ order.dealerName }}</td> 105 + <td>{{ delivery.dealerName }}</td>
106 - <td>{{ formatDate(order.orderDate) }}</td> 106 + <td>{{ formatDate(delivery.deliveryDate) }}</td>
107 - <td>{{ formatCurrency(order.totalAmount) }}</td> 107 + <td>{{ formatCurrency(delivery.totalAmount) }}</td>
108 <td> 108 <td>
109 - <span :class="getDeliveryStatusClass(order.deliveryStatus)"> 109 + <span :class="getDeliveryStatusClass(delivery.deliveryStatus)">
110 - {{ getDeliveryStatusText(order.deliveryStatus) }} 110 + {{ getDeliveryStatusText(delivery.deliveryStatus) }}
111 </span> 111 </span>
112 </td> 112 </td>
113 - <td>{{ formatTime(order.uploadTime || '') }}</td> 113 + <td>{{ formatTime(delivery.createTime || '') }}</td>
114 <td class="action-col"> 114 <td class="action-col">
115 - <button @click="handleView(order)" class="view-btn">👁️ 查看</button> 115 + <button @click="handleView(delivery)" class="view-btn">👁️ 查看</button>
116 </td> 116 </td>
117 </tr> 117 </tr>
118 </tbody> 118 </tbody>
...@@ -409,13 +409,13 @@ ...@@ -409,13 +409,13 @@
409 409
410 <script setup lang="ts"> 410 <script setup lang="ts">
411 import { ref, reactive, computed, onMounted } from 'vue' 411 import { ref, reactive, computed, onMounted } from 'vue'
412 -import { orderApi, type OrderInfo, type OrderQueryReq } from '../../api/order' 412 +import { deliveryApi, type DeliveryInfo, type DeliveryQueryReq } from '../../api/delivery'
413 413
414 // 响应式数据 414 // 响应式数据
415 const loading = ref(false) 415 const loading = ref(false)
416 -const orderList = ref<OrderInfo[]>([]) 416 +const deliveryList = ref<DeliveryInfo[]>([])
417 const showDetailDialog = ref(false) 417 const showDetailDialog = ref(false)
418 -const orderDetail = ref<OrderInfo | null>(null) 418 +const deliveryDetail = ref<DeliveryInfo | null>(null)
419 419
420 // 新增出库相关数据 420 // 新增出库相关数据
421 const showAddDialog = ref(false) 421 const showAddDialog = ref(false)
...@@ -507,21 +507,21 @@ const getPageNumbers = () => { ...@@ -507,21 +507,21 @@ const getPageNumbers = () => {
507 } 507 }
508 508
509 // 方法 509 // 方法
510 -const fetchOrders = async () => { 510 +const fetchDeliveries = async () => {
511 try { 511 try {
512 loading.value = true 512 loading.value = true
513 const params = { ...searchParams, pageNum: pagination.pageNum, pageSize: pagination.pageSize } 513 const params = { ...searchParams, pageNum: pagination.pageNum, pageSize: pagination.pageSize }
514 - const response = await orderApi.getOrderList(params) as any 514 + const response = await deliveryApi.getDeliveryList(params) as any
515 console.log('出库查询API响应:', response) 515 console.log('出库查询API响应:', response)
516 516
517 // 由于request.ts的响应拦截器已经处理了code=200的情况,直接返回data 517 // 由于request.ts的响应拦截器已经处理了code=200的情况,直接返回data
518 if (response && response.records) { 518 if (response && response.records) {
519 - orderList.value = response.records || [] 519 + deliveryList.value = response.records || []
520 pagination.total = response.total || 0 520 pagination.total = response.total || 0
521 pagination.pageNum = response.current || 1 521 pagination.pageNum = response.current || 1
522 pagination.pageSize = response.size || 10 522 pagination.pageSize = response.size || 10
523 } else { 523 } else {
524 - orderList.value = [] 524 + deliveryList.value = []
525 pagination.total = 0 525 pagination.total = 0
526 showMessage('获取出库列表失败', 'error') 526 showMessage('获取出库列表失败', 'error')
527 } 527 }
...@@ -535,7 +535,7 @@ const fetchOrders = async () => { ...@@ -535,7 +535,7 @@ const fetchOrders = async () => {
535 535
536 const handleSearch = () => { 536 const handleSearch = () => {
537 pagination.pageNum = 1 537 pagination.pageNum = 1
538 - fetchOrders() 538 + fetchDeliveries()
539 } 539 }
540 540
541 const handleReset = () => { 541 const handleReset = () => {
...@@ -548,24 +548,24 @@ const handleReset = () => { ...@@ -548,24 +548,24 @@ const handleReset = () => {
548 endDate: '' 548 endDate: ''
549 }) 549 })
550 pagination.pageNum = 1 550 pagination.pageNum = 1
551 - fetchOrders() 551 + fetchDeliveries()
552 } 552 }
553 553
554 -const handleView = async (order: OrderInfo) => { 554 +const handleView = async (delivery: DeliveryInfo) => {
555 try { 555 try {
556 - const response = await orderApi.getOrderDetail(order.orderId) as any 556 + const response = await deliveryApi.getDeliveryDetail(delivery.deliveryId) as any
557 console.log('出库查询详情API响应:', response) 557 console.log('出库查询详情API响应:', response)
558 558
559 // 由于request.ts的响应拦截器已经处理了code=200的情况,直接返回data 559 // 由于request.ts的响应拦截器已经处理了code=200的情况,直接返回data
560 - if (response && response.orderId) { 560 + if (response && response.deliveryId) {
561 - orderDetail.value = response 561 + deliveryDetail.value = response
562 showDetailDialog.value = true 562 showDetailDialog.value = true
563 } else { 563 } else {
564 - showMessage('获取订单详情失败', 'error') 564 + showMessage('获取出库详情失败', 'error')
565 } 565 }
566 } catch (error) { 566 } catch (error) {
567 - console.error('获取订单详情失败:', error) 567 + console.error('获取出库详情失败:', error)
568 - showMessage('获取订单详情失败, 请重试', 'error') 568 + showMessage('获取出库详情失败, 请重试', 'error')
569 } 569 }
570 } 570 }
571 571
...@@ -634,13 +634,13 @@ const handleSubmitAdd = async () => { ...@@ -634,13 +634,13 @@ const handleSubmitAdd = async () => {
634 const handlePageChange = (page: number) => { 634 const handlePageChange = (page: number) => {
635 if (page >= 1 && page <= totalPages.value) { 635 if (page >= 1 && page <= totalPages.value) {
636 pagination.pageNum = page 636 pagination.pageNum = page
637 - fetchOrders() 637 + fetchDeliveries()
638 } 638 }
639 } 639 }
640 640
641 const handlePageSizeChange = () => { 641 const handlePageSizeChange = () => {
642 pagination.pageNum = 1 642 pagination.pageNum = 1
643 - fetchOrders() 643 + fetchDeliveries()
644 } 644 }
645 645
646 const handleTableSearch = () => { 646 const handleTableSearch = () => {
...@@ -648,7 +648,7 @@ const handleTableSearch = () => { ...@@ -648,7 +648,7 @@ const handleTableSearch = () => {
648 } 648 }
649 649
650 const handleTableRefresh = () => { 650 const handleTableRefresh = () => {
651 - fetchOrders() 651 + fetchDeliveries()
652 } 652 }
653 653
654 const handleTableExport = () => { 654 const handleTableExport = () => {
...@@ -666,7 +666,7 @@ const closeDetailDialog = () => { ...@@ -666,7 +666,7 @@ const closeDetailDialog = () => {
666 666
667 // 生命周期 667 // 生命周期
668 onMounted(() => { 668 onMounted(() => {
669 - fetchOrders() 669 + fetchDeliveries()
670 }) 670 })
671 </script> 671 </script>
672 672
......
...@@ -323,11 +323,11 @@ ...@@ -323,11 +323,11 @@
323 323
324 <script setup lang="ts"> 324 <script setup lang="ts">
325 import { ref, reactive, computed, onMounted } from 'vue' 325 import { ref, reactive, computed, onMounted } from 'vue'
326 -import { orderApi, type OrderInfo, type OrderQueryReq } from '../../api/order' 326 +import { invoiceApi, type InvoiceInfo, type InvoiceQueryReq } from '../../api/invoice'
327 327
328 // 响应式数据 328 // 响应式数据
329 const loading = ref(false) 329 const loading = ref(false)
330 -const orderList = ref<OrderInfo[]>([]) 330 +const invoiceList = ref<InvoiceInfo[]>([])
331 const showDialog = ref(false) 331 const showDialog = ref(false)
332 const showDetailDialog = ref(false) 332 const showDetailDialog = ref(false)
333 const isEdit = ref(false) 333 const isEdit = ref(false)
...@@ -424,7 +424,7 @@ const fetchOrders = async () => { ...@@ -424,7 +424,7 @@ const fetchOrders = async () => {
424 try { 424 try {
425 loading.value = true 425 loading.value = true
426 const params = { ...searchParams, pageNum: pagination.pageNum, pageSize: pagination.pageSize } 426 const params = { ...searchParams, pageNum: pagination.pageNum, pageSize: pagination.pageSize }
427 - const response = await orderApi.getOrderList(params) as any 427 + const response = await invoiceApi.getInvoiceList(params) as any
428 console.log('发票管理API响应:', response) 428 console.log('发票管理API响应:', response)
429 429
430 // 由于request.ts的响应拦截器已经处理了code=200的情况,直接返回data 430 // 由于request.ts的响应拦截器已经处理了code=200的情况,直接返回data
...@@ -494,7 +494,7 @@ const handleEdit = (order: OrderInfo) => { ...@@ -494,7 +494,7 @@ const handleEdit = (order: OrderInfo) => {
494 494
495 const handleView = async (order: OrderInfo) => { 495 const handleView = async (order: OrderInfo) => {
496 try { 496 try {
497 - const response = await orderApi.getOrderDetail(order.orderId) as any 497 + const response = await invoiceApi.getInvoiceDetail(invoice.invoiceId) as any
498 console.log('发票管理详情API响应:', response) 498 console.log('发票管理详情API响应:', response)
499 499
500 // 由于request.ts的响应拦截器已经处理了code=200的情况,直接返回data 500 // 由于request.ts的响应拦截器已经处理了code=200的情况,直接返回data
......
This diff is collapsed. Click to expand it.