refactor: Phase 1 - Extract TimeSlotGenerator from God Class
- Create TimeSlot model class in schedule/model/ - Create TimeSlotGenerator component in schedule/generator/ - Modify MartialScheduleArrangeServiceImpl to use TimeSlotGenerator - Remove internal TimeSlot class (now standalone) - Add 11 unit tests for TimeSlotGenerator - All 438 tests passing Related to Issue #11
This commit is contained in:
+10
-87
@@ -25,7 +25,9 @@ import org.springblade.modules.martial.mapper.*;
|
||||
import org.springblade.modules.martial.pojo.entity.*;
|
||||
import org.springblade.modules.martial.config.ScheduleConfig;
|
||||
import org.springblade.modules.martial.service.IMartialScheduleArrangeService;
|
||||
import org.springblade.modules.martial.service.schedule.generator.TimeSlotGenerator;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springblade.modules.martial.service.schedule.model.TimeSlot;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
@@ -55,6 +57,7 @@ public class MartialScheduleArrangeServiceImpl implements IMartialScheduleArrang
|
||||
private final MartialVenueMapper venueMapper;
|
||||
private final MartialProjectMapper projectMapper;
|
||||
private final ScheduleConfig scheduleConfig;
|
||||
private final TimeSlotGenerator timeSlotGenerator;
|
||||
|
||||
@Override
|
||||
public List<Long> getUnlockedCompetitions() {
|
||||
@@ -352,52 +355,14 @@ public class MartialScheduleArrangeServiceImpl implements IMartialScheduleArrang
|
||||
return athleteMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate time slots for competition
|
||||
* @deprecated Use TimeSlotGenerator.generate() directly
|
||||
*/
|
||||
@Deprecated
|
||||
private List<TimeSlot> generateTimeSlots(MartialCompetition competition) {
|
||||
List<TimeSlot> timeSlots = new ArrayList<>();
|
||||
|
||||
LocalDateTime startTime = competition.getCompetitionStartTime();
|
||||
LocalDateTime endTime = competition.getCompetitionEndTime();
|
||||
|
||||
if (startTime == null || endTime == null) {
|
||||
log.warn("赛事时间信息不完整, 使用默认时间段");
|
||||
return timeSlots;
|
||||
}
|
||||
|
||||
LocalDate currentDate = startTime.toLocalDate();
|
||||
LocalDate endDate = endTime.toLocalDate();
|
||||
|
||||
while (!currentDate.isAfter(endDate)) {
|
||||
// 上午时段 (08:00-12:00, 共240分钟)
|
||||
TimeSlot morning = new TimeSlot();
|
||||
morning.setDate(currentDate);
|
||||
morning.setPeriod("morning");
|
||||
morning.setStartTime("08:00");
|
||||
morning.setCapacity(240); // 4小时 = 240分钟
|
||||
timeSlots.add(morning);
|
||||
|
||||
// 下午时段 (14:00-18:00, 共240分钟)
|
||||
TimeSlot afternoon = new TimeSlot();
|
||||
afternoon.setDate(currentDate);
|
||||
afternoon.setPeriod("afternoon");
|
||||
afternoon.setStartTime("14:00");
|
||||
afternoon.setCapacity(240); // 4小时 = 240分钟
|
||||
timeSlots.add(afternoon);
|
||||
|
||||
// 晚上时段 (19:00-22:00, 共180分钟)
|
||||
TimeSlot evening = new TimeSlot();
|
||||
evening.setDate(currentDate);
|
||||
evening.setPeriod("evening");
|
||||
evening.setStartTime("19:00");
|
||||
evening.setCapacity(180); // 3小时 = 180分钟
|
||||
timeSlots.add(evening);
|
||||
|
||||
currentDate = currentDate.plusDays(1);
|
||||
}
|
||||
|
||||
log.info("生成时间段: {}天, 每天3个时段(上午/下午/晚上), 共{}个时段",
|
||||
java.time.temporal.ChronoUnit.DAYS.between(startTime.toLocalDate(), endDate) + 1, timeSlots.size());
|
||||
|
||||
return timeSlots;
|
||||
return timeSlotGenerator.generate(competition);
|
||||
}
|
||||
|
||||
|
||||
@@ -953,48 +918,6 @@ public class MartialScheduleArrangeServiceImpl implements IMartialScheduleArrang
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 内部数据类 ====================
|
||||
|
||||
private static class TimeSlot {
|
||||
private LocalDate date;
|
||||
private String period; // morning/afternoon
|
||||
private String startTime; // 08:30/13:30
|
||||
private Integer capacity; // 容量(分钟)
|
||||
|
||||
// Getters and Setters
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
public void setPeriod(String period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public String getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(String startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Integer getCapacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
public void setCapacity(Integer capacity) {
|
||||
this.capacity = capacity;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ScheduleGroupData {
|
||||
private String groupName;
|
||||
private Long projectId;
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package org.springblade.modules.martial.service.schedule.generator;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.modules.martial.pojo.entity.MartialCompetition;
|
||||
import org.springblade.modules.martial.service.schedule.model.TimeSlot;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Time slot generator for schedule arrangement
|
||||
* Generates available time slots based on competition dates
|
||||
*
|
||||
* @author Refactored from MartialScheduleArrangeServiceImpl
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class TimeSlotGenerator {
|
||||
|
||||
// Default time slot configurations
|
||||
private static final String MORNING_START = "08:00";
|
||||
private static final String AFTERNOON_START = "14:00";
|
||||
private static final String EVENING_START = "19:00";
|
||||
|
||||
private static final int MORNING_CAPACITY = 240; // 4 hours = 240 minutes
|
||||
private static final int AFTERNOON_CAPACITY = 240; // 4 hours = 240 minutes
|
||||
private static final int EVENING_CAPACITY = 180; // 3 hours = 180 minutes
|
||||
|
||||
/**
|
||||
* Generate time slots for a competition
|
||||
*
|
||||
* @param competition the competition entity
|
||||
* @return list of time slots
|
||||
*/
|
||||
public List<TimeSlot> generate(MartialCompetition competition) {
|
||||
if (competition == null) {
|
||||
log.warn("Competition is null, returning empty time slots");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return generate(
|
||||
competition.getCompetitionStartTime(),
|
||||
competition.getCompetitionEndTime()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate time slots between start and end time
|
||||
*
|
||||
* @param startTime competition start time
|
||||
* @param endTime competition end time
|
||||
* @return list of time slots
|
||||
*/
|
||||
public List<TimeSlot> generate(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
List<TimeSlot> timeSlots = new ArrayList<>();
|
||||
|
||||
if (startTime == null || endTime == null) {
|
||||
log.warn("Competition time info incomplete, returning empty time slots");
|
||||
return timeSlots;
|
||||
}
|
||||
|
||||
LocalDate currentDate = startTime.toLocalDate();
|
||||
LocalDate endDate = endTime.toLocalDate();
|
||||
|
||||
while (!currentDate.isAfter(endDate)) {
|
||||
timeSlots.addAll(generateDailySlots(currentDate));
|
||||
currentDate = currentDate.plusDays(1);
|
||||
}
|
||||
|
||||
long days = ChronoUnit.DAYS.between(startTime.toLocalDate(), endDate) + 1;
|
||||
log.info("Generated time slots: {} days, 3 slots per day (morning/afternoon/evening), total {} slots",
|
||||
days, timeSlots.size());
|
||||
|
||||
return timeSlots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate time slots for a single day
|
||||
*
|
||||
* @param date the date
|
||||
* @return list of time slots for that day
|
||||
*/
|
||||
public List<TimeSlot> generateDailySlots(LocalDate date) {
|
||||
List<TimeSlot> slots = new ArrayList<>();
|
||||
|
||||
// Morning slot (08:00-12:00)
|
||||
slots.add(TimeSlot.builder()
|
||||
.date(date)
|
||||
.period("morning")
|
||||
.startTime(MORNING_START)
|
||||
.capacity(MORNING_CAPACITY)
|
||||
.build());
|
||||
|
||||
// Afternoon slot (14:00-18:00)
|
||||
slots.add(TimeSlot.builder()
|
||||
.date(date)
|
||||
.period("afternoon")
|
||||
.startTime(AFTERNOON_START)
|
||||
.capacity(AFTERNOON_CAPACITY)
|
||||
.build());
|
||||
|
||||
// Evening slot (19:00-22:00)
|
||||
slots.add(TimeSlot.builder()
|
||||
.date(date)
|
||||
.period("evening")
|
||||
.startTime(EVENING_START)
|
||||
.capacity(EVENING_CAPACITY)
|
||||
.build());
|
||||
|
||||
return slots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate total capacity in minutes
|
||||
*
|
||||
* @param timeSlots list of time slots
|
||||
* @return total capacity in minutes
|
||||
*/
|
||||
public int calculateTotalCapacity(List<TimeSlot> timeSlots) {
|
||||
return timeSlots.stream()
|
||||
.mapToInt(TimeSlot::getCapacity)
|
||||
.sum();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.springblade.modules.martial.service.schedule.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Time slot model for schedule arrangement
|
||||
* Represents a time period (morning/afternoon/evening) on a specific date
|
||||
*
|
||||
* @author Refactored from MartialScheduleArrangeServiceImpl
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TimeSlot {
|
||||
|
||||
/**
|
||||
* Date of the time slot
|
||||
*/
|
||||
private LocalDate date;
|
||||
|
||||
/**
|
||||
* Period: morning, afternoon, evening
|
||||
*/
|
||||
private String period;
|
||||
|
||||
/**
|
||||
* Start time in HH:mm format (e.g., "08:00", "14:00", "19:00")
|
||||
*/
|
||||
private String startTime;
|
||||
|
||||
/**
|
||||
* Capacity in minutes
|
||||
*/
|
||||
private Integer capacity;
|
||||
|
||||
/**
|
||||
* Get unique key for this time slot
|
||||
*/
|
||||
public String getSlotKey() {
|
||||
return date.toString() + "_" + period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a morning slot
|
||||
*/
|
||||
public boolean isMorning() {
|
||||
return "morning".equals(period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is an afternoon slot
|
||||
*/
|
||||
public boolean isAfternoon() {
|
||||
return "afternoon".equals(period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is an evening slot
|
||||
*/
|
||||
public boolean isEvening() {
|
||||
return "evening".equals(period);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user