Commit 19d36e0087a2c513160ac7b48c2b41c2460a5ca4

Authored by 王彪总
1 parent bddf5f9d

feat(garden): 优化养护计划时间段计算逻辑并调整接口权限控制

- 在 InspectionPlanSaveReqVO 和 MaintainPlanSaveReqVO 中新增 rateValue 字段长度限制(最大6位)
- 替换原有时间段计算方法 calculate 为 calculateNew,提升周期拆分准确性
- 重写 TimeIntervalFrequencyUtil 工具类中的 calculateNew 方法,支持更灵活的时间段划分
- 新增 convertToDaysNew 方法用于将不同周期单位转换为固定天数
- 注释掉 RoadStreetController 中所有接口的权限校验注解,临时放开访问控制
- 更新测试用例,使用新的 calculateNew 方法进行验证
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/inspectionplan/vo/InspectionPlanSaveReqVO.java
... ... @@ -46,6 +46,7 @@ public class InspectionPlanSaveReqVO {
46 46  
47 47 @Schema(description = "频次值", requiredMode = Schema.RequiredMode.REQUIRED)
48 48 @NotEmpty(message = "频次值不能为空")
  49 + @Size(max = 6)
49 50 private String rateValue;
50 51  
51 52 @Schema(description = "周期ID: 0:次;1:日/次;2:周/次;3:月/次;4:季/次;5:半年/次;6:年/次", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
... ...
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/maintainplan/vo/MaintainPlanSaveReqVO.java
... ... @@ -46,6 +46,7 @@ public class MaintainPlanSaveReqVO {
46 46  
47 47 @Schema(description = "频次值", requiredMode = Schema.RequiredMode.REQUIRED)
48 48 @NotEmpty(message = "频次值不能为空")
  49 + @Size(max = 6)
49 50 private String rateValue;
50 51  
51 52 @Schema(description = "周期ID: 1:日/次;2:周/次;3:月/次;4:年/次;5:按次;6:季度;7:半年", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
... ...
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/road/RoadStreetController.java
... ... @@ -40,14 +40,14 @@ public class RoadStreetController {
40 40  
41 41 @PostMapping("/create")
42 42 @Operation(summary = "创建街道")
43   - @PreAuthorize("@ss.hasPermission('garden:road-street:create')")
  43 +// @PreAuthorize("@ss.hasPermission('garden:road-street:create')")
44 44 public CommonResult<Long> createRoadStreet(@Valid @RequestBody RoadStreetSaveReqVO createReqVO) {
45 45 return success(roadStreetService.createRoadStreet(createReqVO));
46 46 }
47 47  
48 48 @PutMapping("/update")
49 49 @Operation(summary = "更新街道")
50   - @PreAuthorize("@ss.hasPermission('garden:road-street:update')")
  50 +// @PreAuthorize("@ss.hasPermission('garden:road-street:update')")
51 51 public CommonResult<Boolean> updateRoadStreet(@Valid @RequestBody RoadStreetSaveReqVO updateReqVO) {
52 52 roadStreetService.updateRoadStreet(updateReqVO);
53 53 return success(true);
... ... @@ -56,7 +56,7 @@ public class RoadStreetController {
56 56 @DeleteMapping("/delete")
57 57 @Operation(summary = "删除街道")
58 58 @Parameter(name = "id", description = "编号", required = true)
59   - @PreAuthorize("@ss.hasPermission('garden:road-street:delete')")
  59 +// @PreAuthorize("@ss.hasPermission('garden:road-street:delete')")
60 60 public CommonResult<Boolean> deleteRoadStreet(@RequestParam("id") Long id) {
61 61 roadStreetService.deleteRoadStreet(id);
62 62 return success(true);
... ... @@ -65,7 +65,7 @@ public class RoadStreetController {
65 65 @DeleteMapping("/delete-list")
66 66 @Parameter(name = "ids", description = "编号", required = true)
67 67 @Operation(summary = "批量删除街道")
68   - @PreAuthorize("@ss.hasPermission('garden:road-street:delete')")
  68 +// @PreAuthorize("@ss.hasPermission('garden:road-street:delete')")
69 69 public CommonResult<Boolean> deleteRoadStreetList(@RequestParam("ids") List<Long> ids) {
70 70 roadStreetService.deleteRoadStreetListByIds(ids);
71 71 return success(true);
... ... @@ -74,7 +74,7 @@ public class RoadStreetController {
74 74 @GetMapping("/get")
75 75 @Operation(summary = "获得街道")
76 76 @Parameter(name = "id", description = "编号", required = true, example = "1024")
77   - @PreAuthorize("@ss.hasPermission('garden:road-street:query')")
  77 +// @PreAuthorize("@ss.hasPermission('garden:road-street:query')")
78 78 public CommonResult<RoadStreetRespVO> getRoadStreet(@RequestParam("id") Long id) {
79 79 RoadStreetDO roadStreet = roadStreetService.getRoadStreet(id);
80 80 return success(BeanUtils.toBean(roadStreet, RoadStreetRespVO.class));
... ... @@ -83,7 +83,7 @@ public class RoadStreetController {
83 83 @GetMapping("/list")
84 84 @Operation(summary = "获得街道列表")
85 85 @Parameter(name = "busi_line", description = "业务线", required = true, example = "1024")
86   - @PreAuthorize("@ss.hasPermission('garden:road-street:query')")
  86 +// @PreAuthorize("@ss.hasPermission('garden:road-street:query')")
87 87 public CommonResult<List<RoadStreetRespVO>> getRoadStreet(@RequestParam("busi_line") @NotBlank String busiLine) {
88 88 List<RoadStreetDO> roadStreet = roadStreetService.getRoadStreetList(busiLine);
89 89 return success(BeanUtils.toBean(roadStreet, RoadStreetRespVO.class));
... ... @@ -91,7 +91,7 @@ public class RoadStreetController {
91 91  
92 92 @GetMapping("/page")
93 93 @Operation(summary = "获得街道分页")
94   - @PreAuthorize("@ss.hasPermission('garden:road-street:query')")
  94 +// @PreAuthorize("@ss.hasPermission('garden:road-street:query')")
95 95 public CommonResult<PageResult<RoadStreetRespVO>> getRoadStreetPage(@Valid RoadStreetPageReqVO pageReqVO) {
96 96 PageResult<RoadStreetDO> pageResult = roadStreetService.getRoadStreetPage(pageReqVO);
97 97 return success(BeanUtils.toBean(pageResult, RoadStreetRespVO.class));
... ... @@ -99,7 +99,7 @@ public class RoadStreetController {
99 99  
100 100 @GetMapping("/export-excel")
101 101 @Operation(summary = "导出街道 Excel")
102   - @PreAuthorize("@ss.hasPermission('garden:road-street:export')")
  102 +// @PreAuthorize("@ss.hasPermission('garden:road-street:export')")
103 103 @ApiAccessLog(operateType = EXPORT)
104 104 public void exportRoadStreetExcel(@Valid RoadStreetPageReqVO pageReqVO,
105 105 HttpServletResponse response) throws IOException {
... ... @@ -110,4 +110,4 @@ public class RoadStreetController {
110 110 BeanUtils.toBean(list, RoadStreetRespVO.class));
111 111 }
112 112  
113   -}
114 113 \ No newline at end of file
  114 +}
... ...
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/maintainplan/MaintainPlanServiceImpl.java
... ... @@ -124,7 +124,7 @@ public class MaintainPlanServiceImpl implements MaintainPlanService {
124 124 calculate.add(periodResult);
125 125 planNum = Integer.parseInt(createReqVO.getRateValue());
126 126 }else{
127   - calculate= TimeIntervalFrequencyUtil.calculate(createReqVO.getBeginTime().toString(), createReqVO.getEndTime().toString(), rateValue, createReqVO.getCycleId());
  127 + calculate= TimeIntervalFrequencyUtil.calculateNew(createReqVO.getBeginTime().toString(), createReqVO.getEndTime().toString(), rateValue, createReqVO.getCycleId());
128 128 if (CollectionUtils.isEmpty(calculate)) {
129 129 log.warn("获取两个时间之间间隔天数错误");
130 130 return CommonResult.error(INSPECTION_CYCLE_ERROR);
... ...
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/timeinterval/TimeIntervalFrequencyUtil.java
... ... @@ -2,6 +2,7 @@ package com.zteits.urbanops.module.garden.util.timeinterval;
2 2  
3 3 import java.time.LocalDate;
4 4 import java.time.format.DateTimeFormatter;
  5 +import java.time.temporal.ChronoUnit;
5 6 import java.util.ArrayList;
6 7 import java.util.Collections;
7 8 import java.util.List;
... ... @@ -38,6 +39,82 @@ public class TimeIntervalFrequencyUtil {
38 39 * @param cycleId 1:日/次;2:周/次;3:月/次;4:年/次;5:按次;6:季度;7:半年
39 40 * @return 划分结果列表
40 41 */
  42 + /**
  43 + * 计算时间段划分结果(基于固定天数换算)
  44 + *
  45 + * @param startStr 开始日期 (yyyy-MM-dd)
  46 + * @param endStr 结束日期 (yyyy-MM-dd)
  47 + * @param freq 频次值,格式 "x/y",其中 x 为每周期次数,y 为周期数量
  48 + * @param cycleId 周期类型:1:日/次;2:周/次;3:月/次;4:年/次;5:按次;6:季度;7:半年
  49 + * @return 时间段划分结果列表,包含每个时间段的开始日期、结束日期和执行次数
  50 + */
  51 + public static List<PeriodResult> calculateNew(String startStr, String endStr, String freq, Integer cycleId) {
  52 + // 解析日期参数
  53 + LocalDate startDate = LocalDate.parse(startStr, FORMATTER);
  54 + LocalDate endDate = LocalDate.parse(endStr, FORMATTER);
  55 +
  56 + // 边界条件:开始日期晚于结束日期时返回空列表
  57 + if (startDate.isAfter(endDate)) {
  58 + return Collections.emptyList();
  59 + }
  60 +
  61 + // 解析频次参数 (格式: "x/y")
  62 + String[] freqParts = freq.split("/", 2);
  63 + if (freqParts.length != 2) {
  64 + throw new IllegalArgumentException(String.format("频次值格式错误,应为 'x/y': %s", freq));
  65 + }
  66 + int timesPerPeriod = Integer.parseInt(freqParts[0]); // 每周期执行次数
  67 + int periodCount = Integer.parseInt(freqParts[1]); // 周期数量
  68 +
  69 + // 计算周期相关天数
  70 + long daysPerPeriod = convertToDaysNew(periodCount, cycleId); // 单个周期的天数
  71 + long totalPeriodDays = daysPerPeriod * periodCount; // 总周期天数
  72 +
  73 + List<PeriodResult> resultList = new ArrayList<>();
  74 + LocalDate segmentStart = startDate;
  75 +
  76 + // 循环划分时间段
  77 + while (!segmentStart.isAfter(endDate)) {
  78 + // 计算当前时间段的理论结束日期(segmentStart + totalPeriodDays - 1)
  79 + LocalDate segmentEnd = safePlusDays(segmentStart, totalPeriodDays - 1);
  80 +
  81 + // 如果理论结束日期超过总结束日期,则截断
  82 + if (segmentEnd.isAfter(endDate)) {
  83 + segmentEnd = endDate;
  84 + }
  85 +
  86 + // 计算当前时间段的实际天数(包含开始和结束日期)
  87 + long daysInSegment = ChronoUnit.DAYS.between(segmentStart, segmentEnd) + 1;
  88 +
  89 + // 计算当前时间段的执行次数:(实际天数/周期天数) * 每周期次数,向上取整
  90 + double proportion = (double) daysInSegment / daysPerPeriod;
  91 + int executionCount = (int) Math.ceil(proportion * timesPerPeriod);
  92 +
  93 + // 添加当前时间段结果
  94 + resultList.add(new PeriodResult(segmentStart, segmentEnd, executionCount));
  95 +
  96 + // 计算下一个时间段的开始日期(当前结束日期的次日)
  97 + LocalDate nextSegmentStart = segmentEnd.plusDays(1);
  98 +
  99 + // 如果下一个开始日期超过总结束日期,则退出循环
  100 + if (nextSegmentStart.isAfter(endDate)) {
  101 + break;
  102 + }
  103 +
  104 + segmentStart = nextSegmentStart;
  105 + }
  106 +
  107 + return resultList;
  108 + }
  109 + /**
  110 + * 计算时间段划分结果(基于固定天数换算)
  111 + *
  112 + * @param startStr 开始日期 (yyyy-MM-dd)
  113 + * @param endStr 结束日期 (yyyy-MM-dd)
  114 + * @param freq 频次值,格式 "x/y"
  115 + * @param cycleId 1:日/次;2:周/次;3:月/次;4:年/次;5:按次;6:季度;7:半年
  116 + * @return 划分结果列表
  117 + */
41 118 public static List<PeriodResult> calculate(String startStr, String endStr, String freq, Integer cycleId) {
42 119 LocalDate start = LocalDate.parse(startStr, FORMATTER);
43 120 LocalDate end = LocalDate.parse(endStr, FORMATTER);
... ... @@ -77,7 +154,36 @@ public class TimeIntervalFrequencyUtil {
77 154  
78 155 return results;
79 156 }
80   -
  157 + /**
  158 + * 将 y 个单位转换为固定天数
  159 + * TIME(0, "次"),
  160 + * DAY(1, "次/日"),
  161 + * WEEK(2, "次/周"),
  162 + * MONTH(3, "次/月"),
  163 + * QUARTER(4, "次/季"),
  164 + * SEMIANNUAL(5, "次/半年"),
  165 + * YEAR(6, "次/年");
  166 + */
  167 + private static long convertToDaysNew(int y, Integer cycleId) {
  168 + switch (cycleId) {
  169 + case 1: // DAY
  170 + return 1;
  171 + case 2: // WEEK
  172 + return (long) 7;
  173 + case 3: // MONTH
  174 + return (long) 30;
  175 + case 6: // YEAR
  176 + return (long) 365;
  177 + case 0: // TIME
  178 + return 9999; // 按次:将整个时间段视为1个周期
  179 + case 4: // QUARTER
  180 + return (long) 90; // 1季度=3个月=90天
  181 + case 5: // SEMIANNUAL
  182 + return (long) 180; // 半年=6个月=180天
  183 + default:
  184 + throw new IllegalArgumentException("无效的周期ID: " + cycleId);
  185 + }
  186 + }
81 187 /**
82 188 * 将 y 个单位转换为固定天数
83 189 * TIME(0, "次"),
... ... @@ -123,52 +229,56 @@ public class TimeIntervalFrequencyUtil {
123 229  
124 230 // ====================== 测试用例 ======================
125 231 public static void main(String[] args) {
126   - //1:日/次;2:周/次;3:月/次;4:年/次
127   - System.out.println("=== 示例1:每2天3次(即:3/2),按日 ===2025-12-01 2025-12-31");
128   - List<PeriodResult> r1 = calculate("2025-12-01", "2025-12-31", "3/2", 1);
129   - r1.forEach(System.out::println);
130   - // 输出:
131   - // 2025-01-01 2025-01-03 1次
132   - // 2025-01-04 2025-01-06 1次
133   - // 2025-01-07 2025-01-07 1次
134   - System.out.println("\n=== 示例2:每2周3次(即:3/2)(14天),按周 ===2025-12-01 2025-12-10");
135   - List<PeriodResult> r2 = calculate("2025-12-01", "2025-12-10", "3/2", 2);
  232 +
  233 + List<PeriodResult> r2 = calculateNew("2026-01-01", "2026-02-15", "7/1", 2);
136 234 r2.forEach(System.out::println);
137   - // 每2周 = 14天
138   - // 2025-01-01 ~ 2025-01-14
139   - // 2025-01-15 ~ 2025-01-28
140   - // 2025-01-29 ~ 2025-02-08(剩余11天)
141   - System.out.println("\n=== 示例3:每2个月4次(即:4/2)(30天),按月 === 2025-09-15 2025-12-31");
142   - List<PeriodResult> r3 = calculate("2025-09-15", "2025-12-31", "4/2", 3);
143   - r3.forEach(System.out::println);
144   - // 每1月 = 30天
145   - // 2025-01-01 ~ 2025-01-30
146   - // 2025-01-31 ~ 2025-02-28(30天?→ 实际是29天,但按30天算)
147   - // 2025-03-01 ~ 2025-03-15(不足)
148   -
149   - System.out.println("\n=== 示例4:每2年1次(即:1/2)(730天),按年 ===2025-01-01 2030-01-01");
150   - List<PeriodResult> r4 = calculate("2025-01-01", "2030-01-01", "1/2", 4);
151   - r4.forEach(System.out::println);
152   - // 每2年 = 730天
153   - // 2025-01-01 ~ 2025-12-26(+729d)
154   - // 2025-12-27 ~ 2027-12-21
155   - // 2027-12-22 ~ 2029-12-16
156   - // 2029-12-17 ~ 2030-01-01(最后一段)
157   - System.out.println("\n=== 示例5:每1年4次(即:4/1),按年(测试)=== 2023-09-15 2025-01-31");
158   - List<PeriodResult> r5 = calculate("2023-09-15", "2025-01-31", "4/1", 4);
159   - r5.forEach(System.out::println);
160   -
161   - // 新增示例:按次、季度、半年
162   - System.out.println("\n=== 示例6:按次单位,整个时间段算1个周期 === 2025-01-01 2025-12-31");
163   - List<PeriodResult> r6 = calculate("2025-01-01", "2025-12-31", "2/1", 5);
164   - r6.forEach(System.out::println);
165   -
166   - System.out.println("\n=== 示例7:每1季度2次(即:2/1),按季度(90天)=== 2025-01-01 2025-12-31");
167   - List<PeriodResult> r7 = calculate("2025-01-01", "2025-12-31", "2/1", 6);
168   - r7.forEach(System.out::println);
169   -
170   - System.out.println("\n=== 示例8:每1半年3次(即:3/1),按半年(180天)=== 2025-01-01 2025-12-31");
171   - List<PeriodResult> r8 = calculate("2025-01-01", "2025-12-31", "3/1", 7);
172   - r8.forEach(System.out::println);
  235 +
  236 +// //1:日/次;2:周/次;3:月/次;4:年/次
  237 +// System.out.println("=== 示例1:每2天3次(即:3/2),按日 ===2025-12-01 2025-12-31");
  238 +// List<PeriodResult> r1 = calculate("2025-12-01", "2025-12-31", "3/2", 1);
  239 +// r1.forEach(System.out::println);
  240 +// // 输出:
  241 +// // 2025-01-01 2025-01-03 1次
  242 +// // 2025-01-04 2025-01-06 1次
  243 +// // 2025-01-07 2025-01-07 1次
  244 +// System.out.println("\n=== 示例2:每2周3次(即:3/2)(14天),按周 ===2025-12-01 2025-12-10");
  245 +// List<PeriodResult> r2 = calculate("2025-12-01", "2025-12-10", "3/2", 2);
  246 +// r2.forEach(System.out::println);
  247 +// // 每2周 = 14天
  248 +// // 2025-01-01 ~ 2025-01-14
  249 +// // 2025-01-15 ~ 2025-01-28
  250 +// // 2025-01-29 ~ 2025-02-08(剩余11天)
  251 +// System.out.println("\n=== 示例3:每2个月4次(即:4/2)(30天),按月 === 2025-09-15 2025-12-31");
  252 +// List<PeriodResult> r3 = calculate("2025-09-15", "2025-12-31", "4/2", 3);
  253 +// r3.forEach(System.out::println);
  254 +// // 每1月 = 30天
  255 +// // 2025-01-01 ~ 2025-01-30
  256 +// // 2025-01-31 ~ 2025-02-28(30天?→ 实际是29天,但按30天算)
  257 +// // 2025-03-01 ~ 2025-03-15(不足)
  258 +//
  259 +// System.out.println("\n=== 示例4:每2年1次(即:1/2)(730天),按年 ===2025-01-01 2030-01-01");
  260 +// List<PeriodResult> r4 = calculate("2025-01-01", "2030-01-01", "1/2", 4);
  261 +// r4.forEach(System.out::println);
  262 +// // 每2年 = 730天
  263 +// // 2025-01-01 ~ 2025-12-26(+729d)
  264 +// // 2025-12-27 ~ 2027-12-21
  265 +// // 2027-12-22 ~ 2029-12-16
  266 +// // 2029-12-17 ~ 2030-01-01(最后一段)
  267 +// System.out.println("\n=== 示例5:每1年4次(即:4/1),按年(测试)=== 2023-09-15 2025-01-31");
  268 +// List<PeriodResult> r5 = calculate("2023-09-15", "2025-01-31", "4/1", 4);
  269 +// r5.forEach(System.out::println);
  270 +//
  271 +// // 新增示例:按次、季度、半年
  272 +// System.out.println("\n=== 示例6:按次单位,整个时间段算1个周期 === 2025-01-01 2025-12-31");
  273 +// List<PeriodResult> r6 = calculate("2025-01-01", "2025-12-31", "2/1", 5);
  274 +// r6.forEach(System.out::println);
  275 +//
  276 +// System.out.println("\n=== 示例7:每1季度2次(即:2/1),按季度(90天)=== 2025-01-01 2025-12-31");
  277 +// List<PeriodResult> r7 = calculate("2025-01-01", "2025-12-31", "2/1", 6);
  278 +// r7.forEach(System.out::println);
  279 +//
  280 +// System.out.println("\n=== 示例8:每1半年3次(即:3/1),按半年(180天)=== 2025-01-01 2025-12-31");
  281 +// List<PeriodResult> r8 = calculate("2025-01-01", "2025-12-31", "3/1", 7);
  282 +// r8.forEach(System.out::println);
173 283 }
174 284 }
... ...