feat: support shared FBA appointments and arrival calendar

This commit is contained in:
2026-10-09 11:01:39 +08:00
parent 4f9433c39a
commit e94271706c
34 changed files with 677 additions and 121 deletions
@@ -37,6 +37,18 @@ import java.util.List;
public class PlatformPortScheduleController {
@Resource private PortScheduleService service;
@GetMapping("/arrival-calendar")
@PreAuthorize("hasAuthority('platform:appointment:list')")
public ApiResponse<List<com.baiyue.firstleg.portschedule.dto.ArrivalCalendarEntry>> arrivalCalendar(
@AuthenticationPrincipal AuthenticatedUser user,
@org.springframework.web.bind.annotation.RequestParam
@org.springframework.format.annotation.DateTimeFormat(iso = org.springframework.format.annotation.DateTimeFormat.ISO.DATE) java.time.LocalDate from,
@org.springframework.web.bind.annotation.RequestParam
@org.springframework.format.annotation.DateTimeFormat(iso = org.springframework.format.annotation.DateTimeFormat.ISO.DATE) java.time.LocalDate to) {
FirstlegScopeGuard.platform(user);
return ApiResponse.success(service.arrivalCalendar(from, to));
}
@GetMapping
@PreAuthorize("hasAuthority('platform:firstleg:port-schedule:list')")
public ApiResponse<PageResult<ScheduleView>> page(@AuthenticationPrincipal AuthenticatedUser user,
@@ -0,0 +1,7 @@
package com.baiyue.firstleg.portschedule.dto;
import java.time.LocalDateTime;
public record ArrivalCalendarEntry(Long containerBookingId, String bookingNo, String containerNo,
String vesselName, String voyageNo, String destinationPortName, String destinationWarehouseCode,
LocalDateTime arrivalAt, String arrivalType) {}
@@ -11,6 +11,26 @@ import org.apache.ibatis.annotations.Update;
@Mapper
public interface PortScheduleMapper extends BaseMapper<PortScheduleEntity> {
@Select("""
SELECT c.id containerBookingId,c.booking_no bookingNo,c.container_no containerNo,
c.vessel_name vesselName,c.voyage_no voyageNo,c.destination_port_name destinationPortName,
c.destination_warehouse_code destinationWarehouseCode,
COALESCE(n.actual_at,c.actual_port_arrival_at,c.estimated_port_arrival_at) arrivalAt,
CASE WHEN COALESCE(n.actual_at,c.actual_port_arrival_at) IS NOT NULL THEN 'ACTUAL' ELSE 'ESTIMATED' END arrivalType
FROM fl_container_booking c
LEFT JOIN fl_carrier_schedule_node_fact n ON n.container_booking_id=c.id
AND n.standard_node='ARRIVED_DESTINATION_PORT' AND n.actual_at IS NOT NULL
AND n.id=(SELECT n2.id FROM fl_carrier_schedule_node_fact n2
WHERE n2.container_booking_id=c.id AND n2.standard_node='ARRIVED_DESTINATION_PORT'
AND n2.actual_at IS NOT NULL ORDER BY n2.observed_at DESC,n2.id DESC LIMIT 1)
WHERE c.record_status='ACTIVE'
AND COALESCE(n.actual_at,c.actual_port_arrival_at,c.estimated_port_arrival_at)>=#{from}
AND COALESCE(n.actual_at,c.actual_port_arrival_at,c.estimated_port_arrival_at)<#{to}
ORDER BY arrivalAt,c.id
""")
java.util.List<com.baiyue.firstleg.portschedule.dto.ArrivalCalendarEntry> arrivalCalendar(
@Param("from") java.time.LocalDateTime from, @Param("to") java.time.LocalDateTime to);
@Select("""
<script>
SELECT * FROM fl_port_schedule
@@ -35,6 +35,10 @@ public class PortScheduleRepository {
return PageResult.from(schedules.selectPage(new Page<>(query.page(), query.size()), query));
}
public PortScheduleEntity find(long id) { return schedules.selectById(id); }
public List<com.baiyue.firstleg.portschedule.dto.ArrivalCalendarEntry> arrivalCalendar(
java.time.LocalDateTime from, java.time.LocalDateTime to) {
return schedules.arrivalCalendar(from, to);
}
public PortScheduleEntity latestForDispatch(long customerId, long oceanBookingId, long containerBookingId) {
return schedules.latestForDispatch(customerId, oceanBookingId, containerBookingId);
}
@@ -48,6 +48,15 @@ public class PortScheduleService {
return detail(required(id));
}
public java.util.List<com.baiyue.firstleg.portschedule.dto.ArrivalCalendarEntry> arrivalCalendar(
java.time.LocalDate from, java.time.LocalDate to) {
if (from == null || to == null || !to.isAfter(from)
|| java.time.temporal.ChronoUnit.DAYS.between(from, to) > 42) {
throw badRequest("日历查询范围必须为1至42天");
}
return repository.arrivalCalendar(from.atStartOfDay(), to.atStartOfDay());
}
public java.util.List<PortScheduleHistoryEntity> history(long id) {
required(id);
return repository.histories(id);