package com.trafficaudit.dataimport.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.trafficaudit.common.Result; import com.trafficaudit.dataimport.entity.CityBusMonthly; import com.trafficaudit.dataimport.entity.CityTaxiMonthly; import com.trafficaudit.dataimport.entity.H2032EnterpriseMonthly; import com.trafficaudit.dataimport.entity.PassengerEnterpriseMonthly; import com.trafficaudit.dataimport.mapper.CityBusMonthlyMapper; import com.trafficaudit.dataimport.mapper.CityTaxiMonthlyMapper; import com.trafficaudit.dataimport.mapper.H2032EnterpriseMonthlyMapper; import com.trafficaudit.dataimport.mapper.PassengerEnterpriseMonthlyMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; 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.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 企业解释:独立于审核结果的解释列表与 AI 分析入口。 * 支持多报表类型:H2032 货运、H2031 公路旅客、CITY_BUS 城市公交、CITY_TAXI 巡游出租。 */ @Slf4j @RestController @RequestMapping("/api/explain") public class ExplainController { @Resource private H2032EnterpriseMonthlyMapper h2032Mapper; @Resource private PassengerEnterpriseMonthlyMapper passengerMapper; @Resource private CityBusMonthlyMapper cityBusMapper; @Resource private CityTaxiMonthlyMapper cityTaxiMapper; @GetMapping("/list") public Result> list(@RequestParam(value = "reportType", defaultValue = "H2032") String reportType, @RequestParam(value = "period", required = false) String period, @RequestParam(value = "keyword", required = false) String keyword, @RequestParam(value = "hasExplanation", defaultValue = "false") boolean hasExplanation, @RequestParam(value = "page", defaultValue = "1") long page, @RequestParam(value = "size", defaultValue = "20") long size) { String kw = keyword == null ? "" : keyword.trim(); boolean hasPeriod = period != null && !period.trim().isEmpty(); long p = Math.max(page, 1); long s = Math.min(Math.max(size, 1), 200); List> records = new ArrayList<>(); long total = 0; if ("H2031".equals(reportType)) { LambdaQueryWrapper w = new LambdaQueryWrapper() .eq(hasPeriod, PassengerEnterpriseMonthly::getReportPeriod, period) .isNotNull(hasExplanation, PassengerEnterpriseMonthly::getVerifyExplanation) .ne(hasExplanation, PassengerEnterpriseMonthly::getVerifyExplanation, "") .like(!kw.isEmpty(), PassengerEnterpriseMonthly::getEnterpriseName, kw) .orderByDesc(PassengerEnterpriseMonthly::getId); Page r = passengerMapper.selectPage(new Page<>(p, s), w); for (PassengerEnterpriseMonthly e : r.getRecords()) { Map row = baseRow(e.getId(), e.getReportPeriod(), e.getRegionCode(), e.getEnterpriseCode(), e.getEnterpriseName(), e.getVerifyExplanation()); row.put("vehicleTotal", e.getVehicleTotal()); row.put("seatTotal", e.getSeatTotal()); row.put("passengerTotal", e.getPassengerTotal()); row.put("turnoverTotal", e.getTurnoverTotal()); row.put("avgDistance", e.getAvgDistanceTotal()); records.add(row); } total = r.getTotal(); } else if ("CITY_BUS".equals(reportType)) { LambdaQueryWrapper w = new LambdaQueryWrapper() .eq(hasPeriod, CityBusMonthly::getReportPeriod, period) .isNotNull(hasExplanation, CityBusMonthly::getVerifyExplanation) .ne(hasExplanation, CityBusMonthly::getVerifyExplanation, "") .like(!kw.isEmpty(), CityBusMonthly::getEnterpriseName, kw) .orderByDesc(CityBusMonthly::getId); Page r = cityBusMapper.selectPage(new Page<>(p, s), w); for (CityBusMonthly e : r.getRecords()) { Map row = baseRow(e.getId(), e.getReportPeriod(), e.getRegionCode(), e.getEnterpriseCode(), e.getEnterpriseName(), e.getVerifyExplanation()); row.put("city", e.getCity()); row.put("opVehicles", e.getOpVehicles()); row.put("passengerVolume", e.getPassengerVolume()); row.put("turnover", e.getTurnover()); row.put("avgDistance", e.getAvgDistance()); records.add(row); } total = r.getTotal(); } else if ("CITY_TAXI".equals(reportType)) { LambdaQueryWrapper w = new LambdaQueryWrapper() .eq(hasPeriod, CityTaxiMonthly::getReportPeriod, period) .isNotNull(hasExplanation, CityTaxiMonthly::getVerifyExplanation) .ne(hasExplanation, CityTaxiMonthly::getVerifyExplanation, "") .like(!kw.isEmpty(), CityTaxiMonthly::getCity, kw) .orderByDesc(CityTaxiMonthly::getId); Page r = cityTaxiMapper.selectPage(new Page<>(p, s), w); for (CityTaxiMonthly e : r.getRecords()) { Map row = baseRow(e.getId(), e.getReportPeriod(), e.getRegionCode(), null, e.getCity(), e.getVerifyExplanation()); row.put("city", e.getCity()); row.put("opVehicles", e.getOpVehicles()); row.put("tripTotal", e.getTripTotal()); row.put("passengerVolume", e.getPassengerVolume()); row.put("turnover", e.getTurnover()); row.put("avgDistance", e.getAvgDistance()); records.add(row); } total = r.getTotal(); } else { LambdaQueryWrapper w = new LambdaQueryWrapper() .eq(hasPeriod, H2032EnterpriseMonthly::getReportPeriod, period) .isNotNull(hasExplanation, H2032EnterpriseMonthly::getVerifyExplanation) .ne(hasExplanation, H2032EnterpriseMonthly::getVerifyExplanation, "") .like(!kw.isEmpty(), H2032EnterpriseMonthly::getEnterpriseName, kw) .orderByDesc(H2032EnterpriseMonthly::getId); Page r = h2032Mapper.selectPage(new Page<>(p, s), w); for (H2032EnterpriseMonthly e : r.getRecords()) { Map row = baseRow(e.getId(), e.getReportPeriod(), e.getRegionCode(), e.getEnterpriseCode(), e.getEnterpriseName(), e.getVerifyExplanation()); row.put("vehicleTotal", e.getVehicleTotal()); row.put("tonsTotal", e.getTonsTotal()); row.put("freightTotal", e.getFreightTotal()); row.put("turnoverTotal", e.getTurnoverTotal()); row.put("avgDistance", e.getAvgDistance()); records.add(row); } total = r.getTotal(); } Map result = new LinkedHashMap<>(); result.put("reportType", reportType); result.put("records", records); result.put("total", total); result.put("current", p); result.put("size", s); return Result.ok(result); } /** * 保存企业解释:更新对应来源表(H2032/H2031/CITY_BUS/CITY_TAXI)行的 verifyExplanation。 * 审核结果页内嵌解释模块与「企业解释」页共用此接口。 */ @PostMapping("/save") public Result save(@RequestParam("reportType") String reportType, @RequestParam("reportId") Long reportId, @RequestParam(value = "explanation", required = false) String explanation) { String exp = explanation == null ? "" : explanation.trim(); boolean ok = false; String t = reportType == null ? "" : reportType; try { switch (t) { case "H2032": { H2032EnterpriseMonthly e = h2032Mapper.selectById(reportId); if (e != null) { e.setVerifyExplanation(exp); h2032Mapper.updateById(e); ok = true; } break; } case "H2031": { PassengerEnterpriseMonthly e = passengerMapper.selectById(reportId); if (e != null) { e.setVerifyExplanation(exp); passengerMapper.updateById(e); ok = true; } break; } case "CITY_BUS": { CityBusMonthly e = cityBusMapper.selectById(reportId); if (e != null) { e.setVerifyExplanation(exp); cityBusMapper.updateById(e); ok = true; } break; } case "CITY_TAXI": { CityTaxiMonthly e = cityTaxiMapper.selectById(reportId); if (e != null) { e.setVerifyExplanation(exp); cityTaxiMapper.updateById(e); ok = true; } break; } default: throw new RuntimeException("不支持的报表类型:" + reportType); } } catch (Exception e) { log.error("explain save error", e); return Result.error("保存失败: " + e.getMessage()); } if (!ok) { return Result.error("未找到对应的数据行(reportId=" + reportId + ")"); } return Result.ok(exp); } private Map baseRow(Long id, String reportPeriod, String regionCode, String enterpriseCode, String enterpriseName, String verifyExplanation) { Map row = new LinkedHashMap<>(); row.put("id", id); row.put("reportPeriod", reportPeriod); row.put("regionCode", regionCode); row.put("enterpriseCode", enterpriseCode); row.put("enterpriseName", enterpriseName); row.put("verifyExplanation", verifyExplanation); return row; } }