feat(crm): 添加销售报表功能模块

- 新增销售报表查询业务对象CrmSalesReportBo,支持多种查询条件
- 创建销售报表控制器CrmSalesReportController,提供汇总数据、订单明细、统计分析等接口
- 实现销售报表数据访问层CrmSalesReportMapper,包含销售汇总、订单明细、销售员统计等查询
- 开发销售报表服务层ICrmSalesReportService及其实现类,处理报表数据逻辑
- 设计销售报表视图对象CrmSalesReportVo,包含汇总信息、订单明细、统计分析等数据结构
- 集成Excel导出功能,支持订单明细、销售员统计、客户等级统计、行业统计的数据导出
- 实现多维度统计分析,包括销售员业绩、客户等级分布、行业分布等统计功能
This commit is contained in:
2025-12-29 10:05:05 +08:00
parent 96b6e844d9
commit 11c21f2a33
7 changed files with 954 additions and 0 deletions

View File

@@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.klp.crm.mapper.CrmSalesReportMapper">
<!-- 通用查询条件 -->
<sql id="selectCondition">
<where>
o.del_flag = 0 AND c.del_flag = 0
<if test="bo.startTime != null">
AND DATE(o.create_time) &gt;= #{bo.startTime}
</if>
<if test="bo.endTime != null">
AND DATE(o.create_time) &lt;= #{bo.endTime}
</if>
<if test="bo.salesmanList != null and bo.salesmanList.size() > 0">
AND o.salesman IN
<foreach collection="bo.salesmanList" item="salesman" open="(" separator="," close=")">
#{salesman}
</foreach>
</if>
<if test="bo.customerIdList != null and bo.customerIdList.size() > 0">
AND o.customer_id IN
<foreach collection="bo.customerIdList" item="customerId" open="(" separator="," close=")">
#{customerId}
</foreach>
</if>
<if test="bo.customerLevelList != null and bo.customerLevelList.size() > 0">
AND c.customer_level IN
<foreach collection="bo.customerLevelList" item="level" open="(" separator="," close=")">
#{level}
</foreach>
</if>
<if test="bo.industryList != null and bo.industryList.size() > 0">
AND c.industry IN
<foreach collection="bo.industryList" item="industry" open="(" separator="," close=")">
#{industry}
</foreach>
</if>
<if test="bo.orderStatusList != null and bo.orderStatusList.size() > 0">
AND o.order_status IN
<foreach collection="bo.orderStatusList" item="status" open="(" separator="," close=")">
#{status}
</foreach>
</if>
<if test="bo.financeStatusList != null and bo.financeStatusList.size() > 0">
AND o.finance_status IN
<foreach collection="bo.financeStatusList" item="status" open="(" separator="," close=")">
#{status}
</foreach>
</if>
<if test="bo.orderTypeList != null and bo.orderTypeList.size() > 0">
AND o.order_type IN
<foreach collection="bo.orderTypeList" item="type" open="(" separator="," close=")">
#{type}
</foreach>
</if>
<if test="bo.minOrderAmount != null">
AND o.order_amount &gt;= #{bo.minOrderAmount}
</if>
<if test="bo.maxOrderAmount != null">
AND o.order_amount &lt;= #{bo.maxOrderAmount}
</if>
<if test="bo.onlyUnpaidOrders != null and bo.onlyUnpaidOrders == true">
AND o.unpaid_amount > 0
</if>
<if test="bo.companyNameKeyword != null and bo.companyNameKeyword != ''">
AND c.company_name LIKE CONCAT('%', #{bo.companyNameKeyword}, '%')
</if>
<if test="bo.orderCodeKeyword != null and bo.orderCodeKeyword != ''">
AND o.order_code LIKE CONCAT('%', #{bo.orderCodeKeyword}, '%')
</if>
<if test="bo.includeObjectionOrders != null and bo.includeObjectionOrders == false">
AND NOT EXISTS (
SELECT 1 FROM crm_sales_objection obj
WHERE obj.order_id = o.order_id AND obj.del_flag = 0
)
</if>
</where>
</sql>
<!-- 查询销售汇总统计数据 -->
<select id="selectSalesSummary" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$SalesSummary">
SELECT
COUNT(o.order_id) as totalOrderCount,
COALESCE(SUM(o.order_amount), 0) as totalSalesAmount,
COUNT(CASE WHEN o.order_status = 3 THEN 1 END) as completedOrderCount,
COALESCE(SUM(CASE WHEN o.order_status = 3 THEN o.order_amount ELSE 0 END), 0) as completedSalesAmount,
COALESCE(SUM(o.unpaid_amount), 0) as totalUnpaidAmount,
COALESCE(AVG(o.order_amount), 0) as avgOrderAmount
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
<include refid="selectCondition"/>
</select>
<!-- 查询订单明细列表 -->
<select id="selectOrderDetailList" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$OrderDetail">
SELECT
o.order_id,
o.order_code,
c.customer_code,
c.company_name,
c.contact_person,
c.customer_level,
c.industry,
o.order_amount,
o.salesman,
o.delivery_date,
o.order_status,
o.finance_status,
o.unpaid_amount,
o.create_time,
COALESCE(item_stats.item_count, 0) as itemCount,
COALESCE(obj_stats.objection_count, 0) as objectionCount
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
LEFT JOIN (
SELECT
order_id,
COUNT(*) as item_count
FROM crm_order_item
WHERE del_flag = 0
GROUP BY order_id
) item_stats ON o.order_id = item_stats.order_id
LEFT JOIN (
SELECT
order_id,
COUNT(*) as objection_count
FROM crm_sales_objection
WHERE del_flag = 0
GROUP BY order_id
) obj_stats ON o.order_id = obj_stats.order_id
<include refid="selectCondition"/>
<choose>
<when test="bo.orderBy != null and bo.orderBy != ''">
ORDER BY ${bo.orderBy}
<if test="bo.sortDirection != null and bo.sortDirection != ''">
${bo.sortDirection}
</if>
</when>
<otherwise>
ORDER BY o.create_time DESC
</otherwise>
</choose>
</select>
<!-- 查询销售员统计数据 -->
<select id="selectSalesmanStats" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$SalesmanStat">
SELECT
o.salesman,
COUNT(o.order_id) as orderCount,
COALESCE(SUM(o.order_amount), 0) as salesAmount,
ROUND(
COALESCE(SUM(o.order_amount), 0) * 100.0 /
NULLIF((SELECT SUM(order_amount) FROM crm_order o2
LEFT JOIN crm_customer c2 ON o2.customer_id = c2.customer_id
<include refid="selectCondition"/>), 0),
2
) as percentage
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
<include refid="selectCondition"/>
GROUP BY o.salesman
ORDER BY salesAmount DESC
</select>
<!-- 查询客户等级统计数据 -->
<select id="selectCustomerLevelStats" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$CustomerLevelStat">
SELECT
c.customer_level,
COUNT(DISTINCT c.customer_id) as customerCount,
COUNT(o.order_id) as orderCount,
COALESCE(SUM(o.order_amount), 0) as salesAmount
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
<include refid="selectCondition"/>
GROUP BY c.customer_level
ORDER BY salesAmount DESC
</select>
<!-- 查询行业统计数据 -->
<select id="selectIndustryStats" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$IndustryStat">
SELECT
COALESCE(c.industry, '未分类') as industry,
COUNT(DISTINCT c.customer_id) as customerCount,
COUNT(o.order_id) as orderCount,
COALESCE(SUM(o.order_amount), 0) as salesAmount
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
<include refid="selectCondition"/>
GROUP BY c.industry
ORDER BY salesAmount DESC
</select>
</mapper>