chengf
2025-08-20 aab1ad64e309fa904cc9cbeba4d76b533a5b6c71
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
<?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="reportFeeServiceDaoImpl">
    <select id="repostInFee" resultType="java.util.Map">
        -- 步骤1:使用传入的yearList作为年份范围(避免递归CTE)
        WITH all_years AS (
        <foreach collection="yearList" item="year" separator="UNION ALL">
            SELECT #{year} AS year
        </foreach>
        ),
        -- 步骤2:生成所有费用类型
        all_fee_types AS (
        SELECT DISTINCT
        f.fee_type_cd,
        COALESCE(dict.`name`, '未知类型') AS fee_type_name
        FROM pay_fee f
        LEFT JOIN t_dict dict ON f.fee_type_cd = dict.status_cd
        ),
        -- 步骤3:生成"类型+年份"全量组合
        all_type_year AS (
        SELECT
        t.fee_type_cd,
        t.fee_type_name,
        y.year AS detail_year
        FROM all_fee_types t
        CROSS JOIN all_years y
        ),
        -- 步骤4:原始数据聚合(按年份列表动态处理)
        original_agg AS (
        SELECT
        f.fee_type_cd,
        COALESCE(dict.`name`, '未知类型') AS fee_type_name,
        d.detail_year,
        -- 核心年度字段
        SUM(DISTINCT d.receivable_amount) AS 该年应缴总额,
        ROUND(SUM(DISTINCT d.receivable_amount)/12, 4) AS 每月费用,
        12 AS 应收月份数,
        ROUND(CASE WHEN SUM(DISTINCT d.receivable_amount) = 0 THEN 0
        ELSE SUM(DISTINCT d.received_amount)/SUM(DISTINCT d.receivable_amount)*100
        END, 2) AS 当年收缴率,
        SUM(DISTINCT d.discount_amount) AS 折扣金额,
        -- 各年实缴(遍历yearList生成字段)
        <foreach collection="yearList" item="y" separator=",">
            SUM(CASE WHEN YEAR(d.pay_fee_time) = #{y} THEN d.received_amount ELSE 0 END) AS ${y}年实缴
        </foreach>,
        -- 其他核心字段
        SUM(DISTINCT d.receivable_amount) AS 当年预算,
        SUM(DISTINCT d.received_amount) AS 当年实缴,  -- 当年实缴=当年实际收到的金额
        SUM(DISTINCT d.discount_amount) AS 当年折扣总额,
        SUM(DISTINCT d.receivable_amount) - SUM(DISTINCT d.received_amount) AS 当年欠款,
        -- 每月应收(遍历monthList生成字段)
        <foreach collection="monthList" item="m" separator=",">
            SUM(DISTINCT CASE WHEN d.detail_month = #{m} THEN d.receivable_amount ELSE 0 END) AS 当年${m}月应收
        </foreach>,
        -- 每月实缴(遍历monthList生成字段)
        <foreach collection="monthList" item="m" separator=",">
            SUM(DISTINCT CASE WHEN d.detail_month = #{m} THEN d.received_amount ELSE 0 END) AS 当年${m}月实缴
        </foreach>
        FROM pay_fee_detail_month d
        INNER JOIN pay_fee f ON d.fee_id = f.fee_id
        LEFT JOIN t_dict dict ON f.fee_type_cd = dict.status_cd
        WHERE d.community_id = #{communityId}
        AND d.status_cd = '0'
        AND d.detail_year BETWEEN #{startYear} AND #{endYear}
        GROUP BY f.fee_type_cd, COALESCE(dict.`name`, '未知类型'), d.detail_year
        ),
        -- 步骤5:全量明细行(关联聚合结果)
        detail_rows AS (
        SELECT
        a.fee_type_cd,
        a.fee_type_name,
        a.detail_year AS 费用所属年份,
        '明细' AS 行类型,
        -- 核心年度字段
        COALESCE(o.该年应缴总额, 0) AS 该年应缴总额,
        COALESCE(o.每月费用, 0) AS 每月费用,
        COALESCE(o.应收月份数, 12) AS 应收月份数,
        COALESCE(o.当年收缴率, 0) AS 当年收缴率,
        COALESCE(o.折扣金额, 0) AS 折扣金额,
        -- 各年实缴(遍历yearList)
        <foreach collection="yearList" item="y" separator=",">
            COALESCE(o.${y}年实缴, 0) AS ${y}年实缴
        </foreach>,
        -- 其他核心字段
        COALESCE(o.当年预算, 0) AS 当年预算,
        COALESCE(o.当年实缴, 0) AS 当年实缴,
        COALESCE(o.当年折扣总额, 0) AS 当年折扣总额,
        COALESCE(o.当年欠款, 0) AS 当年欠款,
        -- 每月应收(遍历monthList)
        <foreach collection="monthList" item="m" separator=",">
            COALESCE(o.当年${m}月应收, 0) AS 当年${m}月应收
        </foreach>,
        -- 每月实缴(遍历monthList)
        <foreach collection="monthList" item="m" separator=",">
            COALESCE(o.当年${m}月实缴, 0) AS 当年${m}月实缴
        </foreach>
        FROM all_type_year a
        LEFT JOIN original_agg o
        ON a.fee_type_cd = o.fee_type_cd
        AND a.detail_year = o.detail_year
        ),
        -- 步骤6:类型总计行(聚合明细行)
        type_total_rows AS (
        SELECT
        fee_type_cd,
        fee_type_name,
        '类型总计' AS 费用所属年份,
        '类型总计' AS 行类型,
        SUM(该年应缴总额) AS 该年应缴总额,
        ROUND(SUM(该年应缴总额) / (12 * COUNT(DISTINCT 费用所属年份)), 4) AS 每月费用,
        12 * COUNT(DISTINCT 费用所属年份) AS 应收月份数,
        ROUND(CASE WHEN SUM(该年应缴总额) = 0 THEN 0
        ELSE SUM(当年实缴) / SUM(该年应缴总额) * 100
        END, 2) AS 当年收缴率,
        SUM(折扣金额) AS 折扣金额,
        -- 各年实缴合计(遍历yearList)
        <foreach collection="yearList" item="y" separator=",">
            SUM(${y}年实缴) AS ${y}年实缴
        </foreach>,
        -- 其他核心字段合计
        SUM(当年预算) AS 当年预算,
        SUM(当年实缴) AS 当年实缴,
        SUM(当年折扣总额) AS 当年折扣总额,
        SUM(当年欠款) AS 当年欠款,
        -- 每月应收合计(遍历monthList)
        <foreach collection="monthList" item="m" separator=",">
            SUM(当年${m}月应收) AS 当年${m}月应收
        </foreach>,
        -- 每月实缴合计(遍历monthList)
        <foreach collection="monthList" item="m" separator=",">
            SUM(当年${m}月实缴) AS 当年${m}月实缴
        </foreach>
        FROM detail_rows
        GROUP BY fee_type_cd, fee_type_name
        ),
        -- 步骤7:总合计行(聚合所有数据)
        grand_total_row AS (
        SELECT
        'ALL' AS fee_type_cd,
        '所有类型总计' AS fee_type_name,
        '总合计' AS 费用所属年份,
        '总合计' AS 行类型,
        SUM(该年应缴总额) AS 该年应缴总额,
        ROUND(SUM(该年应缴总额) / (12 * COUNT(DISTINCT 费用所属年份)), 4) AS 每月费用,
        12 * COUNT(DISTINCT 费用所属年份) AS 应收月份数,
        ROUND(CASE WHEN SUM(该年应缴总额) = 0 THEN 0
        ELSE SUM(当年实缴) / SUM(该年应缴总额) * 100
        END, 2) AS 当年收缴率,
        SUM(折扣金额) AS 折扣金额,
        -- 各年实缴总合计(遍历yearList)
        <foreach collection="yearList" item="y" separator=",">
            SUM(${y}年实缴) AS ${y}年实缴
        </foreach>,
        -- 其他核心字段总合计
        SUM(当年预算) AS 当年预算,
        SUM(当年实缴) AS 当年实缴,
        SUM(当年折扣总额) AS 当年折扣总额,
        SUM(当年欠款) AS 当年欠款,
        -- 每月应收总合计(遍历monthList)
        <foreach collection="monthList" item="m" separator=",">
            SUM(当年${m}月应收) AS 当年${m}月应收
        </foreach>,
        -- 每月实缴总合计(遍历monthList)
        <foreach collection="monthList" item="m" separator=",">
            SUM(当年${m}月实缴) AS 当年${m}月实缴
        </foreach>
        FROM detail_rows
        )
 
        -- 最终结果:合并所有行并排序
        SELECT * FROM (
        SELECT * FROM type_total_rows
        UNION ALL
        SELECT * FROM detail_rows
        UNION ALL
        SELECT * FROM grand_total_row
        ) AS all_rows
        ORDER BY
        CASE
        WHEN 行类型 = '总合计' THEN 2
        WHEN 行类型 = '类型总计' THEN 0
        ELSE 1
        END,
        fee_type_cd,
        CASE WHEN 费用所属年份 = '类型总计' THEN 0 ELSE CAST(费用所属年份 AS UNSIGNED) END
    </select>
    <insert id="saveReport" parameterType="Map">
        INSERT INTO report_query_record (
            id,
            refresh_time,
            end_year,
            community_id,
            community_name,
            report_content,
            operator,
            operator_id,
            query_status,
            create_time,
            update_time
        ) VALUES (
                     #{id},
                     now(),
                     #{endYear},
                     #{communityId},
                     null,
                     #{reportContent},
                     #{operator},
                     null,
                     #{queryStatus},
                     now(),
                     now()
                 )
    </insert>
    <select id="queryReport" resultType="java.util.Map">
        SELECT
        id,
        refresh_time AS refreshTime,
        end_year AS endYear,
        community_id AS communityId,
        community_name AS communityName,
        report_content AS reportContent,
        operator,
        operator_id AS operatorId,
        query_status AS queryStatus,
        create_time AS createTime,
        update_time AS updateTime
        FROM report_query_record
        WHERE 1 = 1
        <if test="communityId != null and communityId != ''">
            AND community_id = #{communityId}
        </if>
        <if test="endYear != null and endYear != ''">
            AND end_year = #{endYear}
        </if>
        <if test="queryStatus != null and queryStatus != ''">
            AND query_status = #{queryStatus}
        </if>
        <if test="operatorId != null and operatorId != ''">
            AND operator_id = #{operatorId}
        </if>
        <if test="startTime != null and startTime != ''">
            AND create_time >= #{startTime}
        </if>
        <if test="endTime != null and endTime != ''">
            AND create_time &lt;= #{endTime}
        </if>
        ORDER BY create_time DESC
        <if test="pageNum != null and pageSize != null">
            LIMIT #{pageNum}, #{pageSize}
        </if>
    </select>
</mapper>