package com.trafficaudit.reportexport.controller; import com.trafficaudit.common.Result; import com.trafficaudit.reportexport.service.ReportExportService; import com.trafficaudit.system.service.OperationLogService; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.net.URLEncoder; import java.util.List; import java.nio.charset.StandardCharsets; @Slf4j @RestController @RequestMapping("/api/report") public class ReportExportController { @Resource private ReportExportService reportService; @Resource private OperationLogService operationLogService; /** 生成_货运量分市州明细.xlsx */ @GetMapping("/export/cityDetail") public ResponseEntity exportCityDetail(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_货运量分市州明细.xlsx", period); return buildResponse(reportService.exportCityDetail(period, mode), "生成_货运量分市州明细.xlsx"); } /** 生成_货运量排名.xlsx */ @GetMapping("/export/freightRank") public ResponseEntity exportFreightRank(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_货运量排名.xlsx", period); return buildResponse(reportService.exportFreightRank(period, mode), "生成_货运量排名.xlsx"); } /** 生成_周转量排名.xlsx */ @GetMapping("/export/turnoverRank") public ResponseEntity exportTurnoverRank(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_周转量排名.xlsx", period); return buildResponse(reportService.exportTurnoverRank(period, mode), "生成_周转量排名.xlsx"); } /** 生成_公路旅客分市州明细.xlsx(month: 报表期 yyyy-MM;year: 年份 yyyy) */ @GetMapping("/export/passengerCityDetail") public ResponseEntity exportPassengerCityDetail(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_公路旅客分市州明细.xlsx", period); return buildResponse(reportService.exportPassengerCityDetail(period, mode), "生成_公路旅客分市州明细.xlsx"); } /** 生成_公路旅客中口径明细.xlsx */ @GetMapping("/export/passengerMidDetail") public ResponseEntity exportPassengerMidDetail(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_公路旅客中口径明细.xlsx", period); return buildResponse(reportService.exportPassengerMidDetail(period, mode), "生成_公路旅客中口径明细.xlsx"); } /** 生成_公路旅客中口径排名.xlsx */ @GetMapping("/export/passengerMidRank") public ResponseEntity exportPassengerMidRank(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_公路旅客中口径排名.xlsx", period); return buildResponse(reportService.exportPassengerMidRank(period, mode), "生成_公路旅客中口径排名.xlsx"); } /** 生成_公路旅客中口径分析.xlsx */ @GetMapping("/export/passengerMidAnalysis") public ResponseEntity exportPassengerMidAnalysis(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_公路旅客中口径分析.xlsx", period); return buildResponse(reportService.exportPassengerMidAnalysis(period, mode), "生成_公路旅客中口径分析.xlsx"); } /** 生成_能运汇总表.xlsx(H204,全省 + 各市州 sheet) */ @GetMapping("/export/energySummary") public ResponseEntity exportEnergySummary(@RequestParam("period") String period) throws Exception { logExport("生成_能运汇总表.xlsx", period); return buildResponse(reportService.exportEnergySummary(period), "生成_能运汇总表.xlsx"); } /** 生成_城市公交客运量分市州明细.xlsx(城市客运第1步,公交) */ @GetMapping("/export/cityBusDetail") public ResponseEntity exportCityBusDetail(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_城市公交客运量分市州明细.xlsx", period); return buildResponse(reportService.exportCityBusDetail(period, mode), "生成_城市公交客运量分市州明细.xlsx"); } /** 生成_巡游出租客运量分市州明细.xlsx(城市客运第2步,巡游出租) */ @GetMapping("/export/cityTaxiDetail") public ResponseEntity exportCityTaxiDetail(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_巡游出租客运量分市州明细.xlsx", period); return buildResponse(reportService.exportCityTaxiDetail(period, mode), "生成_巡游出租客运量分市州明细.xlsx"); } /** 生成_2026年全省预安排计划进度情况汇总.xlsx(投资模块表1) */ @GetMapping("/export/investPlan") public ResponseEntity exportInvestPlan(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_全省预安排计划进度情况汇总.xls", period); return buildResponse(reportService.investPlan(period, mode), "生成_全省预安排计划进度情况汇总.xls"); } /** 生成_"十五五"规划物流项目进展情况.xlsx(投资模块表2) */ @GetMapping("/export/investFiveYearLogistics") public ResponseEntity exportInvestFiveYearLogistics(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_十五五规划物流项目进展情况.xls", period); return buildResponse(reportService.investFiveYearLogistics(period, mode), "生成_十五五规划物流项目进展情况.xls"); } /** 生成_湖北省(客货站场)亿元投资项目.xls(投资模块表3,投资总表+规上项目表两sheet) */ @GetMapping("/export/investBillion") public ResponseEntity exportInvestBillion(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_湖北省(客货站场)亿元投资项目.xls", period); return buildResponse(reportService.investBillion(period, mode), "生成_湖北省(客货站场)亿元投资项目.xls"); } /** 生成_(经济强县项目)交通物流基础设施投资统计报表.xlsx(投资模块表4) */ @GetMapping("/export/investCounty") public ResponseEntity exportInvestCounty(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_经济强县交通物流基础设施投资统计报表.xls", period); return buildResponse(reportService.investCounty(period, mode), "生成_经济强县交通物流基础设施投资统计报表.xls"); } /** 生成_轨道轮渡客运量分市州明细.xlsx(城市客运,轨道/轮渡取自公交源文件) */ @GetMapping("/export/cityRailFerryDetail") public ResponseEntity exportCityRailFerryDetail(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_轨道轮渡客运量分市州明细.xlsx", period); return buildResponse(reportService.exportCityRailFerryDetail(period, mode), "生成_轨道轮渡客运量分市州明细.xlsx"); } /** 生成_城市客运客运量分市州累计.xlsx(城市分市州_模板底稿) */ @GetMapping("/export/cityPassengerCitySum") public ResponseEntity exportCityPassengerCitySum(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_城市客运客运量分市州累计.xlsx", period); return buildResponse(reportService.exportCityPassengerCitySum("导入模板_城市分市州.xlsx", period, mode), "生成_城市客运客运量分市州累计.xlsx"); } /** 生成_城市客运各市州明细表.xlsx(城市客运各市州明细表_模板底稿) */ @GetMapping("/export/cityPassengerDetailSum") public ResponseEntity exportCityPassengerDetailSum(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_城市客运各市州明细表.xlsx", period); return buildResponse(reportService.exportCityPassengerCitySum("导入模板_城市客运各市州明细表.xlsx", period, mode), "生成_城市客运各市州明细表.xlsx"); } /** 生成_城市客运汇总.xlsx(城市汇总_模板底稿) */ @GetMapping("/export/cityPassengerSummary") public ResponseEntity exportCityPassengerSummary(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExport("生成_城市客运汇总.xlsx", period); return buildResponse(reportService.exportCityPassengerSummary(period, mode), "生成_城市客运汇总.xlsx"); } /** 生成_城市客运报表系列.zip(一键打包全部:公交/出租/轨道轮渡明细 + 分市州累计 + 各市州明细表 + 汇总) */ @GetMapping("/export/cityPassengerSeries") public ResponseEntity exportCityPassengerSeries(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExportZip("生成_城市客运报表系列.zip", period); String fileName = String.format("生成_城市客运报表系列_%s.zip", period); String encoded = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20"); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encoded) .contentType(MediaType.parseMediaType("application/zip")) .body(reportService.exportCityPassengerSeries(period, mode)); } /** 生成_货运报表系列.zip(一键打包:明细+排名) */ @GetMapping("/export/freightSeries") public ResponseEntity exportFreightSeries(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExportZip("生成_货运报表系列.zip", period); return zipResponse(reportService.exportFreightSeries(period, mode), String.format("生成_货运报表系列_%s.zip", period)); } /** 生成_公路旅客报表系列.zip(一键打包:分市州明细+中口径明细/排名/分析) */ @GetMapping("/export/passengerSeries") public ResponseEntity exportPassengerSeries(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExportZip("生成_公路旅客报表系列.zip", period); return zipResponse(reportService.exportPassengerSeries(period, mode), String.format("生成_公路旅客报表系列_%s.zip", period)); } /** 生成_投资报表系列.zip(一键打包:预安排/十五五/亿元/经济强县) */ @GetMapping("/export/investSeries") public ResponseEntity exportInvestSeries(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception { logExportZip("生成_投资报表系列.zip", period); return zipResponse(reportService.exportInvestSeries(period, mode), String.format("生成_投资报表系列_%s.zip", period)); } /** 生成_所选报表.zip:types 逗号分隔(前端"生成选中"多选) */ @GetMapping("/export/selected") public ResponseEntity exportSelected(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode, @RequestParam("types") String types) throws Exception { List typeList = new java.util.ArrayList<>(); for (String t : types.split(",")) { String s = t.trim(); if (!s.isEmpty()) typeList.add(s); } logExportZip("生成_所选报表.zip", period); return zipResponse(reportService.exportSelectedSeries(period, mode, typeList), String.format("生成_所选报表_%s.zip", period)); } /** 导出前数据就绪校验:返回每张报表依赖的数据行数/缺失提示(types 逗号分隔) */ @GetMapping("/ready") public Result> exportReady(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode, @RequestParam("types") String types) { List typeList = new java.util.ArrayList<>(); for (String t : types.split(",")) { String s = t.trim(); if (!s.isEmpty()) typeList.add(s); } return Result.ok(reportService.checkExportReady(period, mode, typeList)); } /** 报表数据预览(轻量版):就绪 + 月度覆盖 + 核心指标摘要 + 问题清单(types 逗号分隔) */ @GetMapping("/preview") public Result> reportPreview(@RequestParam("period") String period, @RequestParam(value = "mode", defaultValue = "month") String mode, @RequestParam("types") String types) { List typeList = new java.util.ArrayList<>(); for (String t : types.split(",")) { String s = t.trim(); if (!s.isEmpty()) typeList.add(s); } return Result.ok(reportService.reportPreview(period, mode, typeList)); } private void logExport(String reportName, String period) { operationLogService.record("报表生成", "导出报表", reportName + "(报表期:" + period + ")"); } private void logExportZip(String zipName, String period) { operationLogService.record("报表生成", "导出报表系列", zipName + "(报表期:" + period + ")"); } private ResponseEntity zipResponse(byte[] data, String fileName) throws Exception { String encoded = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20"); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encoded) .contentType(MediaType.parseMediaType("application/zip")) .body(data); } private ResponseEntity buildResponse(byte[] data, String fileName) throws Exception { String encoded = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20"); String type = fileName.toLowerCase().endsWith(".xls") ? "application/vnd.ms-excel" : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encoded) .contentType(MediaType.parseMediaType(type)) .body(data); } }