Răsfoiți Sursa

fix: 修复不动产数据稽查建筑面积变化统计错误

weijianghai 10 luni în urmă
părinte
comite
e5bdf76507

+ 2 - 0
src/main/java/com/nokia/financeapi/config/web/MyDispatcherServlet.java

@@ -15,6 +15,8 @@ public class MyDispatcherServlet extends DispatcherServlet {
      * 上传和返回文件流的接口uri,不替换request和response
      */
     public static final Set<String> UN_WRAPPER = Stream.of(
+            "/house-car/house/data-check/api/getBuildingAreaDiffExport",
+            "/house-car/house/data-check/api/getHouseAbnormalDataExport",
             "/house-car/house/report/api/importData",
             "/house-car/car/data-import/api/dataImport"
     ).collect(Collectors.toSet());

+ 3 - 0
src/main/java/com/nokia/financeapi/config/web/RequestLogHandlerInterceptor.java

@@ -78,6 +78,9 @@ public class RequestLogHandlerInterceptor implements HandlerInterceptor {
             log.info("请求体参数: {}", StringUtils.trimAllWhitespace(body));
         }
         String token = request.getHeader("token");
+        if (!StringUtils.hasText(token) || "undefined".equals(token)) {
+            token = parameters.get("token");
+        }
         log.info("token: {}", token);
         if (!StringUtils.hasText(token)) {
             return forbidden(response);

+ 8 - 1
src/main/java/com/nokia/financeapi/controller/house/HouseDataCheckController.java

@@ -8,6 +8,7 @@ import com.nokia.financeapi.pojo.vo.GetHouseAbnormalDataVo;
 import com.nokia.financeapi.service.house.HouseDataCheckService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -25,12 +26,18 @@ public class HouseDataCheckController {
         this.houseDataCheckService = houseDataCheckService;
     }
 
-    @Operation(summary = "建筑面积变化统计")
+    @Operation(summary = "查询自用面积比较")
     @PostMapping("/getBuildingAreaDiff")
     public R<GetBuildingAreaDiffVo> getBuildingAreaDiff(@Valid @RequestBody GetBuildingAreaDiffDto dto) {
         return houseDataCheckService.getBuildingAreaDiff(dto);
     }
 
+    @Operation(summary = "自用面积比较导出")
+    @GetMapping("/getBuildingAreaDiffExport")
+    public void getBuildingAreaDiffExport(@Valid GetBuildingAreaDiffDto dto) {
+        houseDataCheckService.getBuildingAreaDiffExport(dto);
+    }
+
     @Operation(summary = "异常数据稽核表")
     @PostMapping("/getHouseAbnormalData")
     public R<GetHouseAbnormalDataVo> getHouseAbnormalData(@Valid @RequestBody GetHouseAbnormalDataDto dto) {

+ 84 - 214
src/main/java/com/nokia/financeapi/dao/house/HouseDataCheckDao.java

@@ -1,5 +1,6 @@
 package com.nokia.financeapi.dao.house;
 
+import com.nokia.financeapi.pojo.dto.GetBuildingAreaDiffDto;
 import com.nokia.financeapi.pojo.dto.GetHouseAbnormalDataDto;
 import com.nokia.financeapi.pojo.vo.GetBuildingAreaDiffVo;
 import com.nokia.financeapi.pojo.vo.GetHouseAbnormalDataVo;
@@ -11,260 +12,129 @@ import java.util.List;
 
 @Mapper
 public interface HouseDataCheckDao {
+
     /**
-     * 全省建筑面积变化
+     * 建筑面积变化
      */
     @Select("""
+<script>
 with
 t101 as (
 select
+    area_no,
+    city_no,
     sum(building_area) as building_area_sum_last,
     sum(building_area_self_use) as building_area_self_use_sum_last,
     sum(building_area_idle) as building_area_idle_sum_last
 from
     house.building_month
 where
-    year_month = (
-    select
-        max(year_month)
-    from
-        house.building_month
-    where
-        year_no = 2023
-        )
+    year_month = 202312
+group by
+    area_no,
+    city_no
 ),
 t102 as (
 select
+    area_no,
+    city_no,
     sum(building_area) as building_area_sum_now,
     sum(building_area_self_use) as building_area_self_use_sum_now,
     sum(building_area_idle) as building_area_idle_sum_now
 from
     house.building_month
-where
-    year_month = (
-    select
-        max(year_month)
-    from
-        house.building_month
-    where
-        year_no = 2024
-        )
+<choose>
+  <when test="dto.endDate != null">
+    where year_month = #{dto.endDate}
+  </when>
+  <otherwise>
+    where year_month = (select max(year_month) from house.building_month)
+  </otherwise>
+</choose>
+<if test="dto.areaNo != null and dto.areaNo != ''">
+  and area_no = #{dto.areaNo}
+</if>
+<if test="dto.cityNo != null and dto.cityNo != ''">
+  and city_no = #{dto.cityNo}
+</if>
+group by
+    area_no,
+    city_no
 ),
 t103 as (
 select
-    '全省' as unit_name,
-    round(t101.building_area_sum_last, 2) as building_area_sum_last,
-    round(t101.building_area_self_use_sum_last, 2) as building_area_self_use_sum_last,
-    round(t101.building_area_idle_sum_last, 2) as building_area_idle_sum_last,
-    round(t102.building_area_sum_now, 2) as building_area_sum_now,
-    round(t102.building_area_self_use_sum_now, 2) as building_area_self_use_sum_now,
-    round(t102.building_area_idle_sum_now, 2) as building_area_idle_sum_now,
+    b.id as area_no,
+    b."name" as area_name,
+    a.id as city_no,
+    a."name" as city_name,
+    a."name" as unit_name,
+    coalesce(round(t101.building_area_sum_last,
+    2),
+    0) as building_area_sum_last,
+    coalesce(round(t101.building_area_self_use_sum_last,
+    2),
+    0) as building_area_self_use_sum_last,
+    coalesce(round(t101.building_area_idle_sum_last,
+    2),
+    0) as building_area_idle_sum_last,
+    coalesce(round(t102.building_area_sum_now,
+    2),
+    0) as building_area_sum_now,
+    coalesce(round(t102.building_area_self_use_sum_now,
+    2),
+    0) as building_area_self_use_sum_now,
+    coalesce(round(t102.building_area_idle_sum_now,
+    2),
+    0) as building_area_idle_sum_now,
     case
         when t101.building_area_sum_last = 0 then null
-        else round((t102.building_area_sum_now - t101.building_area_sum_last) / t101.building_area_sum_last * 100, 2)
-    end as building_area_diff,
-    case
-        when t101.building_area_self_use_sum_last = 0 then null
-        else round((t102.building_area_self_use_sum_now - t101.building_area_self_use_sum_last) / t101.building_area_self_use_sum_last * 100, 2)
-    end as building_area_self_use_diff,
-    case
-        when t101.building_area_idle_sum_last = 0 then null
-        else round((t102.building_area_idle_sum_now - t101.building_area_idle_sum_last) / t101.building_area_idle_sum_last * 100, 2)
-    end as building_area_idle_diff
-from
-    t101
-cross join t102
-)
-select
-    *
-from
-    t103
-""")
-    GetBuildingAreaDiffVo getFirstUnitBuildingAreaDiff();
-
-    /**
-     * 二级单位建筑面积变化
-     */
-    @Select("""
-with
-t201 as (
-select
-    area_name,
-    sum(building_area) as building_area_sum_last,
-    sum(building_area_self_use) as building_area_self_use_sum_last,
-    sum(building_area_idle) as building_area_idle_sum_last
-from
-    house.building_month
-where
-    year_month = (
-    select
-        max(year_month)
-    from
-        house.building_month
-    where
-        year_no = 2023
-        )
-group by
-    area_name
-),
-t202 as (
-select
-    area_name,
-    sum(building_area) as building_area_sum_now,
-    sum(building_area_self_use) as building_area_self_use_sum_now,
-    sum(building_area_idle) as building_area_idle_sum_now
-from
-    house.building_month
-where
-    year_month = (
-    select
-        max(year_month)
-    from
-        house.building_month
-    where
-        year_no = 2024
-        )
-group by
-    area_name
-),
-t203 as (
-select
-    coalesce(t201.area_name,
-    t202.area_name) as unit_name,
-    coalesce(t201.area_name,
-    t202.area_name) as area_name,
-    round(t201.building_area_sum_last,
-    2) as building_area_sum_last,
-    round(t201.building_area_self_use_sum_last,
-    2) as building_area_self_use_sum_last,
-    round(t201.building_area_idle_sum_last,
-    2) as building_area_idle_sum_last,
-    round(t202.building_area_sum_now,
-    2) as building_area_sum_now,
-    round(t202.building_area_self_use_sum_now,
-    2) as building_area_self_use_sum_now,
-    round(t202.building_area_idle_sum_now,
-    2) as building_area_idle_sum_now,
-    case
-        when t201.building_area_sum_last = 0 then null
-        else round((t202.building_area_sum_now - t201.building_area_sum_last) / t201.building_area_sum_last * 100,
+        else round((coalesce(t102.building_area_sum_now,
+        0) - coalesce(t101.building_area_sum_last,
+        0)) / t101.building_area_sum_last * 100,
         2)
     end as building_area_diff,
     case
-        when t201.building_area_self_use_sum_last = 0 then null
-        else round((t202.building_area_self_use_sum_now - t201.building_area_self_use_sum_last) / t201.building_area_self_use_sum_last * 100,
+        when t101.building_area_self_use_sum_last = 0 then null
+        else round((coalesce(t102.building_area_self_use_sum_now,
+        0) - coalesce(t101.building_area_self_use_sum_last,
+        0)) / t101.building_area_self_use_sum_last * 100,
         2)
     end as building_area_self_use_diff,
     case
-        when t201.building_area_idle_sum_last = 0 then null
-        else round((t202.building_area_idle_sum_now - t201.building_area_idle_sum_last) / t201.building_area_idle_sum_last * 100,
+        when t101.building_area_idle_sum_last = 0 then null
+        else round((coalesce(t102.building_area_idle_sum_now,
+        0) - coalesce(t101.building_area_idle_sum_last,
+        0)) / t101.building_area_idle_sum_last * 100,
         2)
     end as building_area_idle_diff
 from
-    t201
-full join t202 on
-    t201.area_name = t202.area_name
-),
-t204 as (
-select
-    *
-from
-    t203
-left join house.second_unit_sort on
-    t203.area_name = house.second_unit_sort.second_unit
-order by
-    house.second_unit_sort.sort desc
-)
-select
-    *
-from
-    t204
-""")
-    List<GetBuildingAreaDiffVo> getSecondUnitBuildingAreaDiff();
-
-    /**
-     * 三级单位建筑面积变化
-     */
-    @Select("""
-with
-t301 as (
-select
-    area_name,
-    city_name,
-    sum(building_area) as building_area_sum_last,
-    sum(building_area_self_use) as building_area_self_use_sum_last,
-    sum(building_area_idle) as building_area_idle_sum_last
-from
-    house.building_month
+    common.organization a
+left join common.organization b on
+    a.parent_id = b.id
+left join t101 on
+    a.id = t101.city_no
+left join t102 on
+    a.id = t102.city_no
 where
-    year_month = (
-    select
-        max(year_month)
-    from
-        house.building_month
-    where
-        year_no = 2023
-        )
-group by
-    area_name,
-    city_name
-),
-t302 as (
-select
-    area_name,
-    city_name,
-    sum(building_area) as building_area_sum_now,
-    sum(building_area_self_use) as building_area_self_use_sum_now,
-    sum(building_area_idle) as building_area_idle_sum_now
-from
-    house.building_month
-where
-    year_month = (
-    select
-        max(year_month)
-    from
-        house.building_month
-    where
-        year_no = 2024
-        )
-group by
-    area_name,
-    city_name
-),
-t303 as (
-select
-    coalesce(t301.city_name, t302.city_name) as unit_name,
-    coalesce(t301.area_name, t302.area_name) as area_name,
-    coalesce(t301.city_name, t302.city_name) as city_name,
-    round(t301.building_area_sum_last, 2) as building_area_sum_last,
-    round(t301.building_area_self_use_sum_last, 2) as building_area_self_use_sum_last,
-    round(t301.building_area_idle_sum_last, 2) as building_area_idle_sum_last,
-    round(t302.building_area_sum_now, 2) as building_area_sum_now,
-    round(t302.building_area_self_use_sum_now, 2) as building_area_self_use_sum_now,
-    round(t302.building_area_idle_sum_now, 2) as building_area_idle_sum_now,
-    case
-        when t301.building_area_sum_last = 0 then null
-        else round((t302.building_area_sum_now - t301.building_area_sum_last) / t301.building_area_sum_last * 100, 2)
-    end as building_area_diff,
-    case
-        when t301.building_area_self_use_sum_last = 0 then null
-        else round((t302.building_area_self_use_sum_now - t301.building_area_self_use_sum_last) / t301.building_area_self_use_sum_last * 100, 2)
-    end as building_area_self_use_diff,
-    case
-        when t301.building_area_idle_sum_last = 0 then null
-        else round((t302.building_area_idle_sum_now - t301.building_area_idle_sum_last) / t301.building_area_idle_sum_last * 100, 2)
-    end as building_area_idle_diff
-from
-    t301
-full join t302 on t301.area_name = t302.area_name and t301.city_name = t302.city_name
+    a.grade = 2
+    and a.unhide = 1
+<if test="dto.areaNo != null and dto.areaNo != ''">
+  and a.parent_id = #{dto.areaNo}
+</if>
+<if test="dto.cityNo != null and dto.cityNo != ''">
+  and a.id = #{dto.cityNo}
+</if>
+order by
+    b.order_num,
+    a.order_num
 )
 select
     *
 from
-    t303
-order by area_name, city_name
+    t103
+</script>
 """)
-    List<GetBuildingAreaDiffVo> getThirdUnitBuildingAreaDiff();
+    List<GetBuildingAreaDiffVo> buildingAreaDiff(@Param("dto") GetBuildingAreaDiffDto dto);
 
     /**
      * 获取不动产异常数据稽核最新的日期

+ 4 - 0
src/main/java/com/nokia/financeapi/pojo/dto/GetBuildingAreaDiffDto.java

@@ -7,4 +7,8 @@ import lombok.Data;
 public class GetBuildingAreaDiffDto {
     @Schema(description = "账期", example = "202307")
     private Integer endDate;
+    @Schema(description = "二级组织机构id")
+    private String areaNo;
+    @Schema(description = "三级级组织机构id")
+    private String cityNo;
 }

+ 76 - 5
src/main/java/com/nokia/financeapi/pojo/vo/GetBuildingAreaDiffVo.java

@@ -3,25 +3,29 @@ package com.nokia.financeapi.pojo.vo;
 import io.swagger.v3.oas.annotations.Hidden;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
-import lombok.NoArgsConstructor;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
 import java.util.List;
 
-@NoArgsConstructor
 @Data
 public class GetBuildingAreaDiffVo {
+    @Hidden
+    private String areaNo;
     @Hidden
     private String areaName;
     @Hidden
+    private String cityNo;
+    @Hidden
     private String cityName;
     @Schema(description = "单位名称", example = "全省")
     private String unitName;
-    @Schema(description = "年建筑面积", example = "3345429.01")
+    @Schema(description = "2023年建筑面积", example = "3345429.01")
     private BigDecimal buildingAreaSumLast;
-    @Schema(description = "年建筑面积自用", example = "3345429.01")
+    @Schema(description = "2023年建筑面积自用", example = "3345429.01")
     private BigDecimal buildingAreaSelfUseSumLast;
-    @Schema(description = "年建筑面积闲置", example = "3345429.01")
+    @Schema(description = "2023年建筑面积闲置", example = "3345429.01")
     private BigDecimal buildingAreaIdleSumLast;
     @Schema(description = "当月建筑面积", example = "3345429.01")
     private BigDecimal buildingAreaSumNow;
@@ -37,4 +41,71 @@ public class GetBuildingAreaDiffVo {
     private BigDecimal buildingAreaIdleDiff;
     @Schema(description = "子列表")
     private List<GetBuildingAreaDiffVo> children;
+
+    public GetBuildingAreaDiffVo() {
+        this.areaNo = "";
+        this.areaName = "";
+        this.cityNo = "";
+        this.cityName = "";
+        this.unitName = "";
+        this.buildingAreaSumLast = BigDecimal.ZERO;
+        this.buildingAreaSelfUseSumLast = BigDecimal.ZERO;
+        this.buildingAreaIdleSumLast = BigDecimal.ZERO;
+        this.buildingAreaSumNow = BigDecimal.ZERO;
+        this.buildingAreaSelfUseSumNow = BigDecimal.ZERO;
+        this.buildingAreaIdleSumNow = BigDecimal.ZERO;
+        this.buildingAreaDiff = BigDecimal.ZERO;
+        this.buildingAreaSelfUseDiff = BigDecimal.ZERO;
+        this.buildingAreaIdleDiff = BigDecimal.ZERO;
+        this.children = new ArrayList<>();
+    }
+
+    public GetBuildingAreaDiffVo(String areaNo, String areaName) {
+        this.areaNo = areaNo;
+        this.areaName = areaName;
+        this.cityNo = areaNo;
+        this.cityName = areaName;
+        this.unitName = areaName;
+        this.buildingAreaSumLast = BigDecimal.ZERO;
+        this.buildingAreaSelfUseSumLast = BigDecimal.ZERO;
+        this.buildingAreaIdleSumLast = BigDecimal.ZERO;
+        this.buildingAreaSumNow = BigDecimal.ZERO;
+        this.buildingAreaSelfUseSumNow = BigDecimal.ZERO;
+        this.buildingAreaIdleSumNow = BigDecimal.ZERO;
+        this.buildingAreaDiff = BigDecimal.ZERO;
+        this.buildingAreaSelfUseDiff = BigDecimal.ZERO;
+        this.buildingAreaIdleDiff = BigDecimal.ZERO;
+        this.children = new ArrayList<>();
+    }
+
+    public void update(GetBuildingAreaDiffVo po) {
+        this.buildingAreaSumLast = this.buildingAreaSumLast.add(po.buildingAreaSumLast);
+        this.buildingAreaSelfUseSumLast = this.buildingAreaSelfUseSumLast.add(po.buildingAreaSelfUseSumLast);
+        this.buildingAreaIdleSumLast = this.buildingAreaIdleSumLast.add(po.buildingAreaIdleSumLast);
+        this.buildingAreaSumNow = this.buildingAreaSumNow.add(po.buildingAreaSumNow);
+        this.buildingAreaSelfUseSumNow = this.buildingAreaSelfUseSumNow.add(po.buildingAreaSelfUseSumNow);
+        this.buildingAreaIdleSumNow = this.buildingAreaIdleSumNow.add(po.buildingAreaIdleSumNow);
+        if (this.buildingAreaSumLast.compareTo(BigDecimal.ZERO) != 0) {
+            this.buildingAreaDiff = this.buildingAreaSumNow.subtract(this.buildingAreaSumLast)
+                    .divide(this.buildingAreaSumLast, 4, RoundingMode.HALF_DOWN)
+                    .multiply(new BigDecimal("100"));
+        } else {
+            this.buildingAreaDiff = BigDecimal.ZERO;
+        }
+        if (this.buildingAreaSelfUseSumLast.compareTo(BigDecimal.ZERO) != 0) {
+            this.buildingAreaSelfUseDiff = this.buildingAreaSelfUseSumNow.subtract(this.buildingAreaSelfUseSumLast)
+                    .divide(this.buildingAreaSelfUseSumLast, 4, RoundingMode.HALF_DOWN)
+                    .multiply(new BigDecimal("100"));
+        } else {
+            this.buildingAreaSelfUseDiff = BigDecimal.ZERO;
+        }
+        if (buildingAreaIdleSumLast.compareTo(BigDecimal.ZERO) != 0) {
+            this.buildingAreaIdleDiff = this.buildingAreaIdleSumNow.subtract(this.buildingAreaIdleSumLast)
+                    .divide(this.buildingAreaIdleSumLast, 4, RoundingMode.HALF_DOWN)
+                    .multiply(new BigDecimal("100"));
+        } else {
+            this.buildingAreaIdleDiff = BigDecimal.ZERO;
+        }
+        this.children.add(po);
+    }
 }

+ 331 - 12
src/main/java/com/nokia/financeapi/service/house/HouseDataCheckService.java

@@ -1,16 +1,36 @@
 package com.nokia.financeapi.service.house;
 
+import cn.hutool.core.net.URLEncodeUtil;
 import com.nokia.financeapi.common.R;
 import com.nokia.financeapi.dao.house.HouseDataCheckDao;
 import com.nokia.financeapi.pojo.dto.GetBuildingAreaDiffDto;
 import com.nokia.financeapi.pojo.dto.GetHouseAbnormalDataDto;
 import com.nokia.financeapi.pojo.vo.GetBuildingAreaDiffVo;
 import com.nokia.financeapi.pojo.vo.GetHouseAbnormalDataVo;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
 
+import javax.servlet.http.HttpServletResponse;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
 
+@Slf4j
 @Service
 public class HouseDataCheckService {
     private final HouseDataCheckDao houseDataCheckDao;
@@ -20,22 +40,42 @@ public class HouseDataCheckService {
     }
 
     public R<GetBuildingAreaDiffVo> getBuildingAreaDiff(GetBuildingAreaDiffDto dto) {
-        GetBuildingAreaDiffVo vo = houseDataCheckDao.getFirstUnitBuildingAreaDiff();
-        List<GetBuildingAreaDiffVo> l2 = houseDataCheckDao.getSecondUnitBuildingAreaDiff();
-        vo.setChildren(l2);
-        List<GetBuildingAreaDiffVo> l3 = houseDataCheckDao.getThirdUnitBuildingAreaDiff();
-        for (GetBuildingAreaDiffVo second : l2) {
-            List<GetBuildingAreaDiffVo> l33 = new ArrayList<>();
-            second.setChildren(l33);
-            for (GetBuildingAreaDiffVo third : l3) {
-                if (second.getAreaName().equals(third.getAreaName())) {
-                    l33.add(third);
-                }
-            }
+        GetBuildingAreaDiffVo vo = getBuildingAreaDiffVo(dto);
+        if (vo == null) {
+            return R.ok();
         }
         return R.ok(vo);
     }
 
+    private GetBuildingAreaDiffVo getBuildingAreaDiffVo(GetBuildingAreaDiffDto dto) {
+        if ("全省".equals(dto.getAreaNo())) {
+            dto.setAreaNo(null);
+            dto.setCityNo(null);
+        }
+        // 查询三级单位统计
+        List<GetBuildingAreaDiffVo> pos = houseDataCheckDao.buildingAreaDiff(dto);
+        if (CollectionUtils.isEmpty(pos)) {
+            return null;
+        }
+        // 一级单位统计
+        GetBuildingAreaDiffVo firstUnitPo = new GetBuildingAreaDiffVo();
+        firstUnitPo.setAreaName("全省");
+        firstUnitPo.setCityName("全省");
+        firstUnitPo.setUnitName("全省");
+        LinkedHashMap<String, GetBuildingAreaDiffVo> secondUnitPoMap = new LinkedHashMap<>();
+        // 二级单位统计
+        for (GetBuildingAreaDiffVo houseAgeStatPo : pos) {
+            secondUnitPoMap.putIfAbsent(houseAgeStatPo.getAreaNo(),
+                    new GetBuildingAreaDiffVo(houseAgeStatPo.getAreaNo(), houseAgeStatPo.getAreaName()));
+            GetBuildingAreaDiffVo secondUnitPo = secondUnitPoMap.get(houseAgeStatPo.getAreaNo());
+            secondUnitPo.update(houseAgeStatPo);
+        }
+        for (GetBuildingAreaDiffVo value : secondUnitPoMap.values()) {
+            firstUnitPo.update(value);
+        }
+        return firstUnitPo;
+    }
+
     public R<GetHouseAbnormalDataVo> getHouseAbnormalData(GetHouseAbnormalDataDto dto) {
         Integer endDate = dto.getEndDate();
         // 账期为空则取最新的账期
@@ -64,4 +104,283 @@ public class HouseDataCheckService {
         }
         return R.ok(vo);
     }
+
+    public void getBuildingAreaDiffExport(GetBuildingAreaDiffDto dto) {
+        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder
+                .getRequestAttributes();
+        if (servletRequestAttributes == null) {
+            return;
+        }
+        HttpServletResponse response = servletRequestAttributes.getResponse();
+        if (response == null) {
+            return;
+        }
+        String filename = "数据稽查_自用面积比较"
+                + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + ".xlsx";
+        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncodeUtil.encode(filename));
+        response.setContentType("application/octet-stream");
+        try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
+            writeBuildingAreaDiff(dto, wb);
+            wb.write(response.getOutputStream());
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+
+    private void writeBuildingAreaDiff(GetBuildingAreaDiffDto dto, SXSSFWorkbook wb) {
+        GetBuildingAreaDiffVo firstPo = getBuildingAreaDiffVo(dto);
+        DataFormat dataFormat = wb.createDataFormat();
+        // 数字样式
+        CellStyle numberCellStyle = wb.createCellStyle();
+        numberCellStyle.setDataFormat(dataFormat.getFormat("#,##0.00"));
+        numberCellStyle.setAlignment(HorizontalAlignment.RIGHT);
+        // 默认样式
+        CellStyle baseCellStyle = wb.createCellStyle();
+        baseCellStyle.setAlignment(HorizontalAlignment.CENTER);
+        baseCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+//        // 百分比样式
+//        CellStyle percentCellStyle = wb.createCellStyle();
+//        percentCellStyle.setDataFormat(dataFormat.getFormat("0.00%"));
+//        percentCellStyle.setAlignment(HorizontalAlignment.RIGHT);
+        SXSSFSheet sheet = wb.createSheet();
+        AtomicInteger rowIndex = new AtomicInteger(0);
+        // 表头
+        Row headerRow = sheet.createRow(rowIndex.getAndIncrement());
+        List<String> headers = Stream.of("资产所属单位(一级)", "资产所属单位(二级)", "资产所属单位(三级)",
+                "2023建筑面积(㎡)", "2023建筑面积-自用(㎡)", "2023建筑面积-闲置(㎡)", "当月建筑面积(㎡)", "当月建筑面积-自用(㎡)",
+                "当月建筑面积-闲置(㎡)", "建筑面积变化(%)", "自用面积变化(%)", "闲置面积变化(%)").toList();
+        int headerLength = headers.size();
+        for (int i = 0; i < headerLength; i++) {
+            Cell cell = headerRow.createCell(i);
+            cell.setCellValue(headers.get(i));
+            cell.setCellStyle(baseCellStyle);
+            // 根据内容长度设置列宽
+            int columnWidth = headers.get(i).length() * 256 * 2 + 256;
+            sheet.setColumnWidth(i, columnWidth);
+        }
+        if (firstPo == null) {
+            return;
+        }
+        // 数据
+        AtomicInteger columnIndex1 = new AtomicInteger(0);
+        // 一级单位统计
+        Row row1 = sheet.createRow(rowIndex.getAndIncrement());
+        // 资产所属单位(一级)
+        Cell firstUnitCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getAreaName() != null) {
+            firstUnitCell1.setCellValue(firstPo.getAreaName());
+        }
+        // 二级单位
+        Cell areaNameCell1 = row1.createCell(columnIndex1.getAndIncrement());
+//        if (firstPo.getAreaName() != null) {
+//            areaNameCell1.setCellValue(firstPo.getAreaName());
+//        }
+        // 三级单位
+        Cell cityNameCell1 = row1.createCell(columnIndex1.getAndIncrement());
+//        if (firstPo.getCityName() != null) {
+//            cityNameCell1.setCellValue(firstPo.getCityName());
+//        }
+        // 2023建筑面积
+        Cell buildingAreaSumLastCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getBuildingAreaSumLast() != null) {
+            buildingAreaSumLastCell1.setCellValue(firstPo.getBuildingAreaSumLast().doubleValue());
+        }
+        buildingAreaSumLastCell1.setCellStyle(numberCellStyle);
+        // 2023建筑面积-自用
+        Cell buildingAreaSelfUseSumLastCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getBuildingAreaSelfUseSumLast() != null) {
+            buildingAreaSelfUseSumLastCell1.setCellValue(firstPo.getBuildingAreaSelfUseSumLast().doubleValue());
+        }
+        buildingAreaSelfUseSumLastCell1.setCellStyle(numberCellStyle);
+        // 2023建筑面积-闲置
+        Cell buildingAreaIdleSumLastCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getBuildingAreaIdleSumLast() != null) {
+            buildingAreaIdleSumLastCell1.setCellValue(firstPo.getBuildingAreaIdleSumLast().doubleValue());
+        }
+        buildingAreaIdleSumLastCell1.setCellStyle(numberCellStyle);
+        // 当月建筑面积
+        Cell buildingAreaSumNowCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getBuildingAreaSumNow() != null) {
+            buildingAreaSumNowCell1.setCellValue(firstPo.getBuildingAreaSumNow().doubleValue());
+        }
+        buildingAreaSumNowCell1.setCellStyle(numberCellStyle);
+        // 当月建筑面积-自用
+        Cell buildingAreaSelfUseSumNowCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getBuildingAreaSelfUseSumNow() != null) {
+            buildingAreaSelfUseSumNowCell1.setCellValue(firstPo.getBuildingAreaSelfUseSumNow().doubleValue());
+        }
+        buildingAreaSelfUseSumNowCell1.setCellStyle(numberCellStyle);
+        // 当月建筑面积-闲置
+        Cell buildingAreaIdleSumNowCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getBuildingAreaIdleSumNow() != null) {
+            buildingAreaIdleSumNowCell1.setCellValue(firstPo.getBuildingAreaIdleSumNow().doubleValue());
+        }
+        buildingAreaIdleSumNowCell1.setCellStyle(numberCellStyle);
+        // 建筑面积变化
+        Cell buildingAreaDiffCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getBuildingAreaDiff() != null) {
+            buildingAreaDiffCell1.setCellValue(firstPo.getBuildingAreaDiff().doubleValue());
+        }
+        buildingAreaDiffCell1.setCellStyle(numberCellStyle);
+        // 自用面积变化
+        Cell buildingAreaSelfUseDiffCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getBuildingAreaSelfUseDiff() != null) {
+            buildingAreaSelfUseDiffCell1.setCellValue(firstPo.getBuildingAreaSelfUseDiff().doubleValue());
+        }
+        buildingAreaSelfUseDiffCell1.setCellStyle(numberCellStyle);
+        // 闲置面积变化
+        Cell buildingAreaIdleDiffCell1 = row1.createCell(columnIndex1.getAndIncrement());
+        if (firstPo.getBuildingAreaIdleDiff() != null) {
+            buildingAreaIdleDiffCell1.setCellValue(firstPo.getBuildingAreaIdleDiff().doubleValue());
+        }
+        buildingAreaIdleDiffCell1.setCellStyle(numberCellStyle);
+        // 二级单位统计
+        for (GetBuildingAreaDiffVo secondPo : firstPo.getChildren()) {
+            AtomicInteger columnIndex2 = new AtomicInteger(0);
+            Row row2 = sheet.createRow(rowIndex.getAndIncrement());
+            // 资产所属单位(一级)
+            Cell firstUnitCell2 = row2.createCell(columnIndex2.getAndIncrement());
+//            if (secondPo.getAreaName() != null) {
+//                firstUnitCell2.setCellValue(secondPo.getAreaName());
+//            }
+            // 二级单位
+            Cell areaNameCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getAreaName() != null) {
+                areaNameCell2.setCellValue(secondPo.getAreaName());
+            }
+            // 三级单位
+            Cell cityNameCell2 = row2.createCell(columnIndex2.getAndIncrement());
+//            if (secondPo.getCityName() != null) {
+//                cityNameCell2.setCellValue(secondPo.getCityName());
+//            }
+            // 2023建筑面积
+            Cell buildingAreaSumLastCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getBuildingAreaSumLast() != null) {
+                buildingAreaSumLastCell2.setCellValue(secondPo.getBuildingAreaSumLast().doubleValue());
+            }
+            buildingAreaSumLastCell2.setCellStyle(numberCellStyle);
+            // 2023建筑面积-自用
+            Cell buildingAreaSelfUseSumLastCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getBuildingAreaSelfUseSumLast() != null) {
+                buildingAreaSelfUseSumLastCell2.setCellValue(secondPo.getBuildingAreaSelfUseSumLast().doubleValue());
+            }
+            buildingAreaSelfUseSumLastCell2.setCellStyle(numberCellStyle);
+            // 2023建筑面积-闲置
+            Cell buildingAreaIdleSumLastCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getBuildingAreaIdleSumLast() != null) {
+                buildingAreaIdleSumLastCell2.setCellValue(secondPo.getBuildingAreaIdleSumLast().doubleValue());
+            }
+            buildingAreaIdleSumLastCell2.setCellStyle(numberCellStyle);
+            // 当月建筑面积
+            Cell buildingAreaSumNowCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getBuildingAreaSumNow() != null) {
+                buildingAreaSumNowCell2.setCellValue(secondPo.getBuildingAreaSumNow().doubleValue());
+            }
+            buildingAreaSumNowCell2.setCellStyle(numberCellStyle);
+            // 当月建筑面积-自用
+            Cell buildingAreaSelfUseSumNowCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getBuildingAreaSelfUseSumNow() != null) {
+                buildingAreaSelfUseSumNowCell2.setCellValue(secondPo.getBuildingAreaSelfUseSumNow().doubleValue());
+            }
+            buildingAreaSelfUseSumNowCell2.setCellStyle(numberCellStyle);
+            // 当月建筑面积-闲置
+            Cell buildingAreaIdleSumNowCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getBuildingAreaIdleSumNow() != null) {
+                buildingAreaIdleSumNowCell2.setCellValue(secondPo.getBuildingAreaIdleSumNow().doubleValue());
+            }
+            buildingAreaIdleSumNowCell2.setCellStyle(numberCellStyle);
+            // 建筑面积变化
+            Cell buildingAreaDiffCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getBuildingAreaDiff() != null) {
+                buildingAreaDiffCell2.setCellValue(secondPo.getBuildingAreaDiff().doubleValue());
+            }
+            buildingAreaDiffCell2.setCellStyle(numberCellStyle);
+            // 自用面积变化
+            Cell buildingAreaSelfUseDiffCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getBuildingAreaSelfUseDiff() != null) {
+                buildingAreaSelfUseDiffCell2.setCellValue(secondPo.getBuildingAreaSelfUseDiff().doubleValue());
+            }
+            buildingAreaSelfUseDiffCell2.setCellStyle(numberCellStyle);
+            // 闲置面积变化
+            Cell buildingAreaIdleDiffCell2 = row2.createCell(columnIndex2.getAndIncrement());
+            if (secondPo.getBuildingAreaIdleDiff() != null) {
+                buildingAreaIdleDiffCell2.setCellValue(secondPo.getBuildingAreaIdleDiff().doubleValue());
+            }
+            buildingAreaIdleDiffCell2.setCellStyle(numberCellStyle);
+            // 三级单位统计
+            for (GetBuildingAreaDiffVo thirdPo : secondPo.getChildren()) {
+                AtomicInteger columnIndex3 = new AtomicInteger(0);
+                Row row3 = sheet.createRow(rowIndex.getAndIncrement());
+                // 资产所属单位(一级)
+                Cell firstUnitCell3 = row3.createCell(columnIndex3.getAndIncrement());
+//                if (thirdPo.getAreaName() != null) {
+//                    firstUnitCell3.setCellValue(thirdPo.getAreaName());
+//                }
+                // 二级单位
+                Cell areaNameCell3 = row3.createCell(columnIndex3.getAndIncrement());
+//                if (thirdPo.getAreaName() != null) {
+//                    areaNameCell3.setCellValue(thirdPo.getAreaName());
+//                }
+                // 三级单位
+                Cell cityNameCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getCityName() != null) {
+                    cityNameCell3.setCellValue(thirdPo.getCityName());
+                }
+                // 2023建筑面积
+                Cell buildingAreaSumLastCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getBuildingAreaSumLast() != null) {
+                    buildingAreaSumLastCell3.setCellValue(thirdPo.getBuildingAreaSumLast().doubleValue());
+                }
+                buildingAreaSumLastCell3.setCellStyle(numberCellStyle);
+                // 2023建筑面积-自用
+                Cell buildingAreaSelfUseSumLastCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getBuildingAreaSelfUseSumLast() != null) {
+                    buildingAreaSelfUseSumLastCell3.setCellValue(thirdPo.getBuildingAreaSelfUseSumLast().doubleValue());
+                }
+                buildingAreaSelfUseSumLastCell3.setCellStyle(numberCellStyle);
+                // 2023建筑面积-闲置
+                Cell buildingAreaIdleSumLastCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getBuildingAreaIdleSumLast() != null) {
+                    buildingAreaIdleSumLastCell3.setCellValue(thirdPo.getBuildingAreaIdleSumLast().doubleValue());
+                }
+                buildingAreaIdleSumLastCell3.setCellStyle(numberCellStyle);
+                // 当月建筑面积
+                Cell buildingAreaSumNowCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getBuildingAreaSumNow() != null) {
+                    buildingAreaSumNowCell3.setCellValue(thirdPo.getBuildingAreaSumNow().doubleValue());
+                }
+                buildingAreaSumNowCell3.setCellStyle(numberCellStyle);
+                // 当月建筑面积-自用
+                Cell buildingAreaSelfUseSumNowCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getBuildingAreaSelfUseSumNow() != null) {
+                    buildingAreaSelfUseSumNowCell3.setCellValue(thirdPo.getBuildingAreaSelfUseSumNow().doubleValue());
+                }
+                buildingAreaSelfUseSumNowCell3.setCellStyle(numberCellStyle);
+                // 当月建筑面积-闲置
+                Cell buildingAreaIdleSumNowCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getBuildingAreaIdleSumNow() != null) {
+                    buildingAreaIdleSumNowCell3.setCellValue(thirdPo.getBuildingAreaIdleSumNow().doubleValue());
+                }
+                buildingAreaIdleSumNowCell3.setCellStyle(numberCellStyle);
+                // 建筑面积变化
+                Cell buildingAreaDiffCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getBuildingAreaDiff() != null) {
+                    buildingAreaDiffCell3.setCellValue(thirdPo.getBuildingAreaDiff().doubleValue());
+                }
+                buildingAreaDiffCell3.setCellStyle(numberCellStyle);
+                // 自用面积变化
+                Cell buildingAreaSelfUseDiffCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getBuildingAreaSelfUseDiff() != null) {
+                    buildingAreaSelfUseDiffCell3.setCellValue(thirdPo.getBuildingAreaSelfUseDiff().doubleValue());
+                }
+                buildingAreaSelfUseDiffCell3.setCellStyle(numberCellStyle);
+                // 闲置面积变化
+                Cell buildingAreaIdleDiffCell3 = row3.createCell(columnIndex3.getAndIncrement());
+                if (thirdPo.getBuildingAreaIdleDiff() != null) {
+                    buildingAreaIdleDiffCell3.setCellValue(thirdPo.getBuildingAreaIdleDiff().doubleValue());
+                }
+                buildingAreaIdleDiffCell3.setCellStyle(numberCellStyle);
+            }
+        }
+    }
 }