源代码续
package com.campus.express.repository;
import com.campus.express.model.Notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
@Repository
public interface NotificationRepository extends JpaRepository<Notification, Long> {
Page<Notification> findByReceiverIdAndReceiverType(Long receiverId, Integer receiverType, Pageable pageable);
Page<Notification> findByReceiverIdAndReceiverTypeAndReadStatus(
Long receiverId, Integer receiverType, Integer readStatus, Pageable pageable);
Page<Notification> findByType(Integer type, Pageable pageable);
Page<Notification> findByChannel(Integer channel, Pageable pageable);
Page<Notification> findBySendStatus(Integer sendStatus, Pageable pageable);
Page<Notification> findByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
List<Notification> findByBusinessIdAndBusinessType(Long businessId, Integer businessType);
@Modifying
@Query("UPDATE Notification n SET n.readStatus = :readStatus, n.updatedTime = :updatedTime WHERE n.id = :id")
int updateReadStatus(@Param("id") Long id, @Param("readStatus") Integer readStatus, @Param("updatedTime") LocalDateTime updatedTime);
@Modifying
@Query("UPDATE Notification n SET n.readStatus = :readStatus, n.updatedTime = :updatedTime WHERE n.id IN :ids")
int batchUpdateReadStatus(@Param("ids") List<Long> ids, @Param("readStatus") Integer readStatus, @Param("updatedTime") LocalDateTime updatedTime);
@Modifying
@Query("UPDATE Notification n SET n.sendStatus = :sendStatus, n.failReason = :failReason, n.updatedTime = :updatedTime WHERE n.id = :id")
int updateSendStatus(@Param("id") Long id, @Param("sendStatus") Integer sendStatus, @Param("failReason") String failReason, @Param("updatedTime") LocalDateTime updatedTime);
@Modifying
@Query("UPDATE Notification n SET n.retryCount = :retryCount, n.nextRetryTime = :nextRetryTime, n.updatedTime = :updatedTime WHERE n.id = :id")
int updateRetryInfo(@Param("id") Long id, @Param("retryCount") Integer retryCount, @Param("nextRetryTime") LocalDateTime nextRetryTime, @Param("updatedTime") LocalDateTime updatedTime);
List<Notification> findBySendStatusAndNextRetryTimeLessThanEqual(Integer sendStatus, LocalDateTime nextRetryTime);
long countByReceiverIdAndReceiverTypeAndReadStatus(Long receiverId, Integer receiverType, Integer readStatus);
long countByType(Integer type);
long countByChannel(Integer channel);
long countBySendStatus(Integer sendStatus);
}
express-service\src\main\java\com\campus\express\repository\NotificationTemplateRepository.java
package com.campus.express.repository;
import com.campus.express.model.NotificationTemplate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Repository
public interface NotificationTemplateRepository extends JpaRepository<NotificationTemplate, Long> {
Optional<NotificationTemplate> findByCode(String code);
Page<NotificationTemplate> findByNameContaining(String name, Pageable pageable);
Page<NotificationTemplate> findByType(Integer type, Pageable pageable);
Page<NotificationTemplate> findByChannel(Integer channel, Pageable pageable);
Page<NotificationTemplate> findByStatus(Integer status, Pageable pageable);
List<NotificationTemplate> findByTypeAndChannel(Integer type, Integer channel);
List<NotificationTemplate> findByTypeAndStatus(Integer type, Integer status);
List<NotificationTemplate> findByChannelAndStatus(Integer channel, Integer status);
@Modifying
@Query("UPDATE NotificationTemplate t SET t.status = :status, t.updatedTime = :updatedTime WHERE t.id = :id")
int updateStatus(@Param("id") Long id, @Param("status") Integer status, @Param("updatedTime") LocalDateTime updatedTime);
boolean existsByCode(String code);
long countByType(Integer type);
long countByChannel(Integer channel);
long countByStatus(Integer status);
}
express-service\src\main\java\com\campus\express\service\CabinetCellService.java
package com.campus.express.service;
import com.campus.express.dto.CabinetCellDTO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface CabinetCellService {
CabinetCellDTO getCellById(Long id);
CabinetCellDTO getCellByCabinetIdAndCellNumber(Long cabinetId, String cellNumber);
List<CabinetCellDTO> getCellsByCabinetId(Long cabinetId);
List<CabinetCellDTO> getCellsByCabinetIdAndStatus(Long cabinetId, Integer status);
CabinetCellDTO getCellByExpressId(Long expressId);
Page<CabinetCellDTO> getCellsByCabinetIdPaged(Long cabinetId, Pageable pageable);
CabinetCellDTO updateCellStatus(Long id, Integer status);
CabinetCellDTO assignExpressToCell(Long cellId, Long expressId);
CabinetCellDTO retrieveExpressFromCell(Long cellId);
List<CabinetCellDTO> getAvailableCellsByCabinetIdAndSize(Long cabinetId, Integer size);
long countCellsByCabinetIdAndStatus(Long cabinetId, Integer status);
long countCellsByCabinetIdAndSize(Long cabinetId, Integer size);
CabinetCellDTO createCell(Long cabinetId, String cellNumber, Integer size);
void deleteCell(Long id);
List<CabinetCellDTO> batchCreateCells(Long cabinetId, Integer smallCount, Integer mediumCount, Integer largeCount);
}
express-service\src\main\java\com\campus\express\service\CabinetService.java
package com.campus.express.service;
import com.campus.express.dto.CabinetCreateRequest;
import com.campus.express.dto.CabinetDTO;
import com.campus.express.dto.CabinetUpdateRequest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface CabinetService {
CabinetDTO createCabinet(CabinetCreateRequest request);
CabinetDTO getCabinetById(Long id);
CabinetDTO getCabinetByNumber(String cabinetNumber);
CabinetDTO updateCabinet(Long id, CabinetUpdateRequest request);
void deleteCabinet(Long id);
Page<CabinetDTO> getAllCabinets(Pageable pageable);
Page<CabinetDTO> searchCabinets(String keyword, Pageable pageable);
Page<CabinetDTO> getCabinetsByStatus(Integer status, Pageable pageable);
List<CabinetDTO> getCabinetsByManagerId(Long managerId);
Page<CabinetDTO> getAvailableCabinets(Pageable pageable);
Page<CabinetDTO> getCabinetsByLocation(String location, Pageable pageable);
long countCabinetsByStatus(Integer status);
long countCabinetsByManagerId(Long managerId);
CabinetDTO updateCabinetStatus(Long id, Integer status);
CabinetDTO assignCabinetManager(Long id, Long managerId, String managerName, String managerPhone);
CabinetDTO updateAvailableCells(Long id);
void initializeCabinetCells(Long cabinetId, Integer smallCount, Integer mediumCount, Integer largeCount);
}
express-service\src\main\java\com\campus\express\service\DeliveryAreaService.java
package com.campus.express.service;
import com.campus.express.dto.DeliveryAreaDTO;
import com.campus.express.dto.DeliveryAreaCreateRequest;
import com.campus.express.dto.DeliveryAreaUpdateRequest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface DeliveryAreaService {
DeliveryAreaDTO createArea(DeliveryAreaCreateRequest request);
DeliveryAreaDTO getAreaById(Long id);
DeliveryAreaDTO getAreaByCode(String areaCode);
DeliveryAreaDTO updateArea(Long id, DeliveryAreaUpdateRequest request);
void deleteArea(Long id);
Page<DeliveryAreaDTO> getAllAreas(Pageable pageable);
Page<DeliveryAreaDTO> searchAreasByName(String name, Pageable pageable);
Page<DeliveryAreaDTO> getAreasByStatus(Integer status, Pageable pageable);
List<DeliveryAreaDTO> getAreasByParentId(Long parentId);
List<DeliveryAreaDTO> getAreasByLevel(Integer level);
DeliveryAreaDTO updateAreaStatus(Long id, Integer status);
List<DeliveryAreaDTO> getAreaTree();
DeliveryAreaDTO getAreaByCoordinates(Double longitude, Double latitude);
boolean isCoordinateInArea(Long areaId, Double longitude, Double latitude);
double calculateDistance(Double startLongitude, Double startLatitude, Double endLongitude, Double endLatitude);
Double getDeliveryFeeByArea(Long areaId);
long countAreasByStatus(Integer status);
long countAreasByLevel(Integer level);
}
express-service\src\main\java\com\campus\express\service\DeliveryRouteService.java
package com.campus.express.service;
import com.campus.express.dto.DeliveryRouteDTO;
import com.campus.express.dto.DeliveryRouteCreateRequest;
import com.campus.express.dto.DeliveryRouteUpdateRequest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface DeliveryRouteService {
DeliveryRouteDTO createRoute(DeliveryRouteCreateRequest request);
DeliveryRouteDTO getRouteById(Long id);
DeliveryRouteDTO updateRoute(Long id, DeliveryRouteUpdateRequest request);
void deleteRoute(Long id);
Page<DeliveryRouteDTO> getAllRoutes(Pageable pageable);
Page<DeliveryRouteDTO> searchRoutesByName(String name, Pageable pageable);
Page<DeliveryRouteDTO> getRoutesByStatus(Integer status, Pageable pageable);
List<DeliveryRouteDTO> getRoutesByArea(String area);
List<DeliveryRouteDTO> getRoutesByCourierId(Long courierId);
DeliveryRouteDTO assignCourierToRoute(Long routeId, Long courierId, String courierName);
DeliveryRouteDTO updateRouteStatus(Long routeId, Integer status);
List<DeliveryRouteDTO> getRoutesByAreaAndStatus(String area, Integer status);
DeliveryRouteDTO getOptimalRoute(String startPoint, String endPoint, List<String> waypoints);
long countRoutesByStatus(Integer status);
long countRoutesByArea(String area);
long countRoutesByCourierId(Long courierId);
}
express-service\src\main\java\com\campus\express\service\DeliveryService.java
package com.campus.express.service;
import com.campus.express.dto.DeliveryDTO;
import com.campus.express.dto.DeliveryCreateRequest;
import com.campus.express.dto.DeliveryUpdateRequest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.time.LocalDateTime;
import java.util.List;
public interface DeliveryService {
DeliveryDTO createDelivery(DeliveryCreateRequest request);
DeliveryDTO getDeliveryById(Long id);
DeliveryDTO updateDelivery(Long id, DeliveryUpdateRequest request);
void deleteDelivery(Long id);
Page<DeliveryDTO> getAllDeliveries(Pageable pageable);
Page<DeliveryDTO> getDeliveriesByCourierId(Long courierId, Pageable pageable);
Page<DeliveryDTO> getDeliveriesByStatus(Integer status, Pageable pageable);
DeliveryDTO getDeliveryByExpressId(Long expressId);
Page<DeliveryDTO> getDeliveriesByArea(String area, Pageable pageable);
Page<DeliveryDTO> getDeliveriesByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
Page<DeliveryDTO> getDeliveriesByPlannedDeliveryTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
DeliveryDTO assignCourier(Long deliveryId, Long courierId, String courierName, String courierPhone);
DeliveryDTO updateDeliveryStatus(Long deliveryId, Integer status, String remark);
DeliveryDTO startDelivery(Long deliveryId);
DeliveryDTO completeDelivery(Long deliveryId, String deliveryCode);
DeliveryDTO cancelDelivery(Long deliveryId, String reason);
String generateDeliveryCode(Long deliveryId);
boolean verifyDeliveryCode(Long deliveryId, String deliveryCode);
long countDeliveriesByCourierId(Long courierId);
long countDeliveriesByStatus(Integer status);
long countDeliveriesByArea(String area);
long countDeliveriesByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
}
express-service\src\main\java\com\campus\express\service\ExpressService.java
package com.campus.express.service;
import com.campus.express.dto.ExpressCreateRequest;
import com.campus.express.dto.ExpressDTO;
import com.campus.express.dto.ExpressUpdateRequest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.time.LocalDateTime;
import java.util.List;
public interface ExpressService {
ExpressDTO createExpress(ExpressCreateRequest request);
ExpressDTO getExpressById(Long id);
ExpressDTO getExpressByTrackingNumber(String trackingNumber);
ExpressDTO updateExpress(Long id, ExpressUpdateRequest request);
void deleteExpress(Long id);
Page<ExpressDTO> getAllExpress(Pageable pageable);
Page<ExpressDTO> getExpressByUserId(Long userId, Pageable pageable);
Page<ExpressDTO> getExpressByCourierId(Long courierId, Pageable pageable);
Page<ExpressDTO> getExpressByCabinetId(Long cabinetId, Pageable pageable);
Page<ExpressDTO> getExpressByStatus(Integer status, Pageable pageable);
Page<ExpressDTO> searchExpressByRecipient(String keyword, Pageable pageable);
ExpressDTO assignCourier(Long expressId, Long courierId, String courierName, String courierPhone);
ExpressDTO assignCabinet(Long expressId, Long cabinetId, String cellNumber);
ExpressDTO updateExpressStatus(Long expressId, Integer status, Long operatorId, Integer operatorType, String operatorName, String description);
ExpressDTO signExpress(Long expressId, Long userId, String userName);
long countExpressByUserId(Long userId);
long countExpressByCourierId(Long courierId);
long countExpressByStatus(Integer status);
Page<ExpressDTO> getExpressByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
String generatePickupCode(Long expressId);
boolean verifyPickupCode(Long expressId, String pickupCode);
}
express-service\src\main\java\com\campus\express\service\ExpressTrackingService.java
package com.campus.express.service;
import com.campus.express.dto.ExpressTrackingDTO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.time.LocalDateTime;
import java.util.List;
public interface ExpressTrackingService {
ExpressTrackingDTO createTracking(Long expressId, String trackingNumber, Integer operationType,
String description, Long operatorId, Integer operatorType,
String operatorName, String location, String remark);
ExpressTrackingDTO getTrackingById(Long id);
List<ExpressTrackingDTO> getTrackingsByExpressId(Long expressId);
List<ExpressTrackingDTO> getTrackingsByTrackingNumber(String trackingNumber);
Page<ExpressTrackingDTO> getTrackingsByOperationType(Integer operationType, Pageable pageable);
Page<ExpressTrackingDTO> getTrackingsByOperatorId(Long operatorId, Pageable pageable);
Page<ExpressTrackingDTO> getTrackingsByOperatorType(Integer operatorType, Pageable pageable);
Page<ExpressTrackingDTO> getTrackingsByTimeRange(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
List<ExpressTrackingDTO> getTrackingsByExpressIdAndOperationType(Long expressId, Integer operationType);
long countTrackingsByExpressId(Long expressId);
long countTrackingsByOperationType(Integer operationType);
void deleteTracking(Long id);
ExpressTrackingDTO getLatestTracking(Long expressId);
Page<ExpressTrackingDTO> getAllTrackings(Pageable pageable);
}
express-service\src\main\java\com\campus\express\service\NotificationSender.java
package com.campus.express.service;
import com.campus.express.model.Notification;
public interface NotificationSender {
boolean send(Notification notification);
int getSupportedChannel();
}
express-service\src\main\java\com\campus\express\service\NotificationService.java
package com.campus.express.service;
import com.campus.express.dto.NotificationCreateRequest;
import com.campus.express.dto.NotificationDTO;
import com.campus.express.dto.NotificationSendRequest;
import com.campus.express.dto.NotificationUpdateRequest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
public interface NotificationService {
NotificationDTO createNotification(NotificationCreateRequest request);
NotificationDTO getNotificationById(Long id);
NotificationDTO updateNotification(Long id, NotificationUpdateRequest request);
void deleteNotification(Long id);
Page<NotificationDTO> getNotifications(Pageable pageable);
Page<NotificationDTO> getNotificationsByReceiver(Long receiverId, Integer receiverType, Pageable pageable);
Page<NotificationDTO> getNotificationsByReceiverAndReadStatus(
Long receiverId, Integer receiverType, Integer readStatus, Pageable pageable);
Page<NotificationDTO> getNotificationsByType(Integer type, Pageable pageable);
Page<NotificationDTO> getNotificationsByChannel(Integer channel, Pageable pageable);
Page<NotificationDTO> getNotificationsBySendStatus(Integer sendStatus, Pageable pageable);
Page<NotificationDTO> getNotificationsByCreatedTimeBetween(
LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
List<NotificationDTO> getNotificationsByBusiness(Long businessId, Integer businessType);
List<NotificationDTO> sendNotification(NotificationSendRequest request);
NotificationDTO markAsRead(Long id);
int batchMarkAsRead(List<Long> ids);
int markAllAsRead(Long receiverId, Integer receiverType);
NotificationDTO retrySendNotification(Long id);
long countUnreadNotifications(Long receiverId, Integer receiverType);
Map<String, Long> countNotifications(Map<String, Object> params);
}
express-service\src\main\java\com\campus\express\service\NotificationTemplateService.java
package com.campus.express.service;
import com.campus.express.dto.NotificationTemplateCreateRequest;
import com.campus.express.dto.NotificationTemplateDTO;
import com.campus.express.dto.NotificationTemplateUpdateRequest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Map;
public interface NotificationTemplateService {
NotificationTemplateDTO createNotificationTemplate(NotificationTemplateCreateRequest request);
NotificationTemplateDTO getNotificationTemplateById(Long id);
NotificationTemplateDTO getNotificationTemplateByCode(String code);
NotificationTemplateDTO updateNotificationTemplate(Long id, NotificationTemplateUpdateRequest request);
void deleteNotificationTemplate(Long id);
Page<NotificationTemplateDTO> getNotificationTemplates(Pageable pageable);
Page<NotificationTemplateDTO> getNotificationTemplatesByName(String name, Pageable pageable);
Page<NotificationTemplateDTO> getNotificationTemplatesByType(Integer type, Pageable pageable);
Page<NotificationTemplateDTO> getNotificationTemplatesByChannel(Integer channel, Pageable pageable);
Page<NotificationTemplateDTO> getNotificationTemplatesByStatus(Integer status, Pageable pageable);
List<NotificationTemplateDTO> getNotificationTemplatesByTypeAndChannel(Integer type, Integer channel);
List<NotificationTemplateDTO> getNotificationTemplatesByTypeAndStatus(Integer type, Integer status);
List<NotificationTemplateDTO> getNotificationTemplatesByChannelAndStatus(Integer channel, Integer status);
NotificationTemplateDTO updateTemplateStatus(Long id, Integer status);
boolean isTemplateCodeExists(String code);
Map<String, String> renderTemplate(String templateCode, Map<String, Object> params);
Map<String, Long> countNotificationTemplates(Map<String, Object> params);
}
express-service\src\main\java\com\campus\express\service\impl\CabinetCellServiceImpl.java
package com.campus.express.service.impl;
import com.campus.express.dto.CabinetCellDTO;
import com.campus.express.exception.ResourceNotFoundException;
import com.campus.express.model.CabinetCell;
import com.campus.express.repository.CabinetCellRepository;
import com.campus.express.service.CabinetCellService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class CabinetCellServiceImpl implements CabinetCellService {
private final CabinetCellRepository cabinetCellRepository;
@Override
public CabinetCellDTO getCellById(Long id) {
CabinetCell cell = cabinetCellRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("格口不存在,ID: " + id));
return convertToDTO(cell);
}
@Override
public CabinetCellDTO getCellByCabinetIdAndCellNumber(Long cabinetId, String cellNumber) {
CabinetCell cell = cabinetCellRepository.findByCabinetIdAndCellNumber(cabinetId, cellNumber)
.orElseThrow(() -> new ResourceNotFoundException("格口不存在,柜子ID: " + cabinetId + ",格口编号: " + cellNumber));
return convertToDTO(cell);
}
@Override
public List<CabinetCellDTO> getCellsByCabinetId(Long cabinetId) {
return cabinetCellRepository.findByCabinetId(cabinetId).stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
public List<CabinetCellDTO> getCellsByCabinetIdAndStatus(Long cabinetId, Integer status) {
return cabinetCellRepository.findByCabinetIdAndStatus(cabinetId, status).stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
public CabinetCellDTO getCellByExpressId(Long expressId) {
CabinetCell cell = cabinetCellRepository.findByExpressId(expressId)
.orElseThrow(() -> new ResourceNotFoundException("未找到存放该快递的格口,快递ID: " + expressId));
return convertToDTO(cell);
}
@Override
public Page<CabinetCellDTO> getCellsByCabinetIdPaged(Long cabinetId, Pageable pageable) {
return cabinetCellRepository.findByCabinetId(cabinetId, pageable).map(this::convertToDTO);
}
@Override
@Transactional
public CabinetCellDTO updateCellStatus(Long id, Integer status) {
CabinetCell cell = cabinetCellRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("格口不存在,ID: " + id));
cell.setStatus(status);
CabinetCell updatedCell = cabinetCellRepository.save(cell);
return convertToDTO(updatedCell);
}
@Override
@Transactional
public CabinetCellDTO assignExpressToCell(Long cellId, Long expressId) {
CabinetCell cell = cabinetCellRepository.findById(cellId)
.orElseThrow(() -> new ResourceNotFoundException("格口不存在,ID: " + cellId));
if (cell.getStatus() != 0) {
throw new IllegalStateException("格口不可用,当前状态: " + getStatusDesc(cell.getStatus()));
}
cell.setExpressId(expressId);
cell.setStatus(1);
cell.setStorageTime(LocalDateTime.now());
CabinetCell updatedCell = cabinetCellRepository.save(cell);
return convertToDTO(updatedCell);
}
@Override
@Transactional
public CabinetCellDTO retrieveExpressFromCell(Long cellId) {
CabinetCell cell = cabinetCellRepository.findById(cellId)
.orElseThrow(() -> new ResourceNotFoundException("格口不存在,ID: " + cellId));
if (cell.getStatus() != 1) {
throw new IllegalStateException("格口中没有快递,当前状态: " + getStatusDesc(cell.getStatus()));
}
cell.setExpressId(null);
cell.setStatus(0);
cell.setRetrievalTime(LocalDateTime.now());
CabinetCell updatedCell = cabinetCellRepository.save(cell);
return convertToDTO(updatedCell);
}
@Override
public List<CabinetCellDTO> getAvailableCellsByCabinetIdAndSize(Long cabinetId, Integer size) {
return cabinetCellRepository.findByCabinetIdAndSizeAndStatus(cabinetId, size, 0).stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
public long countCellsByCabinetIdAndStatus(Long cabinetId, Integer status) {
return cabinetCellRepository.countByCabinetIdAndStatus(cabinetId, status);
}
@Override
public long countCellsByCabinetIdAndSize(Long cabinetId, Integer size) {
return cabinetCellRepository.countByCabinetIdAndSize(cabinetId, size);
}
@Override
@Transactional
public CabinetCellDTO createCell(Long cabinetId, String cellNumber, Integer size) {
if (cabinetCellRepository.findByCabinetIdAndCellNumber(cabinetId, cellNumber).isPresent()) {
throw new IllegalArgumentException("格口编号已存在,柜子ID: " + cabinetId + ",格口编号: " + cellNumber);
}
CabinetCell cell = CabinetCell.builder()
.cabinetId(cabinetId)
.cellNumber(cellNumber)
.size(size)
.status(0)
.build();
CabinetCell savedCell = cabinetCellRepository.save(cell);
return convertToDTO(savedCell);
}
@Override
@Transactional
public void deleteCell(Long id) {
if (!cabinetCellRepository.existsById(id)) {
throw new ResourceNotFoundException("格口不存在,ID: " + id);
}
cabinetCellRepository.deleteById(id);
}
@Override
@Transactional
public List<CabinetCellDTO> batchCreateCells(Long cabinetId, Integer smallCount, Integer mediumCount, Integer largeCount) {
List<CabinetCell> cells = new ArrayList<>();
int cellIndex = 1;
for (int i = 0; i < smallCount; i++) {
String cellNumber = String.format("S%03d", cellIndex++);
CabinetCell cell = CabinetCell.builder()
.cabinetId(cabinetId)
.cellNumber(cellNumber)
.size(0)
.status(0)
.build();
cells.add(cell);
}
cellIndex = 1;
for (int i = 0; i < mediumCount; i++) {
String cellNumber = String.format("M%03d", cellIndex++);
CabinetCell cell = CabinetCell.builder()
.cabinetId(cabinetId)
.cellNumber(cellNumber)
.size(1)
.status(0)
.build();
cells.add(cell);
}
cellIndex = 1;
for (int i = 0; i < largeCount; i++) {
String cellNumber = String.format("L%03d", cellIndex++);
CabinetCell cell = CabinetCell.builder()
.cabinetId(cabinetId)
.cellNumber(cellNumber)
.size(2)
.status(0)
.build();
cells.add(cell);
}
List<CabinetCell> savedCells = cabinetCellRepository.saveAll(cells);
return savedCells.stream().map(this::convertToDTO).collect(Collectors.toList());
}
private CabinetCellDTO convertToDTO(CabinetCell cell) {
return CabinetCellDTO.builder()
.id(cell.getId())
.cabinetId(cell.getCabinetId())
.cellNumber(cell.getCellNumber())
.size(cell.getSize())
.sizeDesc(getSizeDesc(cell.getSize()))
.status(cell.getStatus())
.statusDesc(getStatusDesc(cell.getStatus()))
.expressId(cell.getExpressId())
.storageTime(cell.getStorageTime())
.retrievalTime(cell.getRetrievalTime())
.remark(cell.getRemark())
.createdTime(cell.getCreatedTime())
.updatedTime(cell.getUpdatedTime())
.build();
}
private String getSizeDesc(Integer size) {
if (size == null) {
return null;
}
switch (size) {
case 0:
return "小";
case 1:
return "中";
case 2:
return "大";
default:
return "未知大小";
}
}
private String getStatusDesc(Integer status) {
if (status == null) {
return null;
}
switch (status) {
case 0:
return "空闲";
case 1:
return "占用";
case 2:
return "故障";
default:
return "未知状态";
}
}
}
express-service\src\main\java\com\campus\express\service\impl\CabinetServiceImpl.java
package com.campus.express.service.impl;
import com.campus.express.dto.CabinetCreateRequest;
import com.campus.express.dto.CabinetDTO;
import com.campus.express.dto.CabinetUpdateRequest;
import com.campus.express.exception.ResourceNotFoundException;
import com.campus.express.model.Cabinet;
import com.campus.express.repository.CabinetRepository;
import com.campus.express.service.CabinetCellService;
import com.campus.express.service.CabinetService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class CabinetServiceImpl implements CabinetService {
private final CabinetRepository cabinetRepository;
private final CabinetCellService cabinetCellService;
@Override
@Transactional
public CabinetDTO createCabinet(CabinetCreateRequest request) {
if (cabinetRepository.findByCabinetNumber(request.getCabinetNumber()).isPresent()) {
throw new IllegalArgumentException("柜子编号已存在: " + request.getCabinetNumber());
}
int totalCells = 0;
if (request.getSmallCellCount() != null) {
totalCells += request.getSmallCellCount();
}
if (request.getMediumCellCount() != null) {
totalCells += request.getMediumCellCount();
}
if (request.getLargeCellCount() != null) {
totalCells += request.getLargeCellCount();
}
if (totalCells == 0) {
totalCells = request.getTotalCells();
}
Cabinet cabinet = Cabinet.builder()
.cabinetNumber(request.getCabinetNumber())
.name(request.getName())
.location(request.getLocation())
.status(request.getStatus())
.totalCells(totalCells)
.availableCells(totalCells)
.managerId(request.getManagerId())
.managerName(request.getManagerName())
.managerPhone(request.getManagerPhone())
.remark(request.getRemark())
.build();
Cabinet savedCabinet = cabinetRepository.save(cabinet);
initializeCabinetCells(
savedCabinet.getId(),
request.getSmallCellCount() != null ? request.getSmallCellCount() : 0,
request.getMediumCellCount() != null ? request.getMediumCellCount() : 0,
request.getLargeCellCount() != null ? request.getLargeCellCount() : totalCells
);
return convertToDTO(savedCabinet);
}
@Override
public CabinetDTO getCabinetById(Long id) {
Cabinet cabinet = cabinetRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("快递柜不存在,ID: " + id));
return convertToDTO(cabinet);
}
@Override
public CabinetDTO getCabinetByNumber(String cabinetNumber) {
Cabinet cabinet = cabinetRepository.findByCabinetNumber(cabinetNumber)
.orElseThrow(() -> new ResourceNotFoundException("快递柜不存在,编号: " + cabinetNumber));
return convertToDTO(cabinet);
}
@Override
@Transactional
public CabinetDTO updateCabinet(Long id, CabinetUpdateRequest request) {
Cabinet cabinet = cabinetRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("快递柜不存在,ID: " + id));
if (request.getName() != null) {
cabinet.setName(request.getName());
}
if (request.getLocation() != null) {
cabinet.setLocation(request.getLocation());
}
if (request.getStatus() != null) {
cabinet.setStatus(request.getStatus());
}
if (request.getManagerId() != null) {
cabinet.setManagerId(request.getManagerId());
cabinet.setManagerName(request.getManagerName());
cabinet.setManagerPhone(request.getManagerPhone());
}
if (request.getRemark() != null) {
cabinet.setRemark(request.getRemark());
}
Cabinet updatedCabinet = cabinetRepository.save(cabinet);
return convertToDTO(updatedCabinet);
}
@Override
@Transactional
public void deleteCabinet(Long id) {
if (!cabinetRepository.existsById(id)) {
throw new ResourceNotFoundException("快递柜不存在,ID: " + id);
}
cabinetRepository.deleteById(id);
}
@Override
public Page<CabinetDTO> getAllCabinets(Pageable pageable) {
return cabinetRepository.findAll(pageable).map(this::convertToDTO);
}
@Override
public Page<CabinetDTO> searchCabinets(String keyword, Pageable pageable) {
return cabinetRepository.findByNameOrLocationContaining(keyword, pageable).map(this::convertToDTO);
}
@Override
public Page<CabinetDTO> getCabinetsByStatus(Integer status, Pageable pageable) {
return cabinetRepository.findByStatus(status, pageable).map(this::convertToDTO);
}
@Override
public List<CabinetDTO> getCabinetsByManagerId(Long managerId) {
return cabinetRepository.findByManagerId(managerId).stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
public Page<CabinetDTO> getAvailableCabinets(Pageable pageable) {
return cabinetRepository.findByAvailableCellsGreaterThan(0, pageable).map(this::convertToDTO);
}
@Override
public Page<CabinetDTO> getCabinetsByLocation(String location, Pageable pageable) {
return cabinetRepository.findByLocationContaining(location, pageable).map(this::convertToDTO);
}
@Override
public long countCabinetsByStatus(Integer status) {
return cabinetRepository.countByStatus(status);
}
@Override
public long countCabinetsByManagerId(Long managerId) {
return cabinetRepository.countByManagerId(managerId);
}
@Override
@Transactional
public CabinetDTO updateCabinetStatus(Long id, Integer status) {
Cabinet cabinet = cabinetRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("快递柜不存在,ID: " + id));
cabinet.setStatus(status);
Cabinet updatedCabinet = cabinetRepository.save(cabinet);
return convertToDTO(updatedCabinet);
}
@Override
@Transactional
public CabinetDTO assignCabinetManager(Long id, Long managerId, String managerName, String managerPhone) {
Cabinet cabinet = cabinetRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("快递柜不存在,ID: " + id));
cabinet.setManagerId(managerId);
cabinet.setManagerName(managerName);
cabinet.setManagerPhone(managerPhone);
Cabinet updatedCabinet = cabinetRepository.save(cabinet);
return convertToDTO(updatedCabinet);
}
@Override
@Transactional
public CabinetDTO updateAvailableCells(Long id) {
Cabinet cabinet = cabinetRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("快递柜不存在,ID: " + id));
long availableCells = cabinetCellService.countCellsByCabinetIdAndStatus(id, 0);
cabinet.setAvailableCells((int) availableCells);
Cabinet updatedCabinet = cabinetRepository.save(cabinet);
return convertToDTO(updatedCabinet);
}
@Override
@Transactional
public void initializeCabinetCells(Long cabinetId, Integer smallCount, Integer mediumCount, Integer largeCount) {
cabinetCellService.batchCreateCells(cabinetId, smallCount, mediumCount, largeCount);
}
private CabinetDTO convertToDTO(Cabinet cabinet) {
return CabinetDTO.builder()
.id(cabinet.getId())
.cabinetNumber(cabinet.getCabinetNumber())
.name(cabinet.getName())
.location(cabinet.getLocation())
.status(cabinet.getStatus())
.statusDesc(getStatusDesc(cabinet.getStatus()))
.totalCells(cabinet.getTotalCells())
.availableCells(cabinet.getAvailableCells())
.smallCellCount((int) cabinetCellService.countCellsByCabinetIdAndSize(cabinet.getId(), 0))
.mediumCellCount((int) cabinetCellService.countCellsByCabinetIdAndSize(cabinet.getId(), 1))
.largeCellCount((int) cabinetCellService.countCellsByCabinetIdAndSize(cabinet.getId(), 2))
.managerId(cabinet.getManagerId())
.managerName(cabinet.getManagerName())
.managerPhone(cabinet.getManagerPhone())
.remark(cabinet.getRemark())
.createdTime(cabinet.getCreatedTime())
.updatedTime(cabinet.getUpdatedTime())
.build();
}
private String getStatusDesc(Integer status) {
if (status == null) {
return null;
}
switch (status) {
case 0:
return "停用";
case 1:
return "启用";
default:
return "未知状态";
}
}
}
express-service\src\main\java\com\campus\express\service\impl\DeliveryAreaServiceImpl.java
package com.campus.express.service.impl;
import com.campus.express.dto.DeliveryAreaCreateRequest;
import com.campus.express.dto.DeliveryAreaDTO;
import com.campus.express.dto.DeliveryAreaUpdateRequest;
import com.campus.express.exception.ResourceNotFoundException;
import com.campus.express.model.DeliveryArea;
import com.campus.express.repository.DeliveryAreaRepository;
import com.campus.express.service.DeliveryAreaService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Slf4j
public class DeliveryAreaServiceImpl implements DeliveryAreaService {
private final DeliveryAreaRepository deliveryAreaRepository;
@Override
@Transactional
public DeliveryAreaDTO createDeliveryArea(DeliveryAreaCreateRequest request) {
log.info("Creating delivery area with name: {}", request.getName());
DeliveryArea deliveryArea = new DeliveryArea();
BeanUtils.copyProperties(request, deliveryArea);
if (deliveryArea.getStatus() == null) {
deliveryArea.setStatus(1);
}
deliveryArea.setCreatedTime(LocalDateTime.now());
deliveryArea.setUpdatedTime(LocalDateTime.now());
DeliveryArea savedArea = deliveryAreaRepository.save(deliveryArea);
log.info("Delivery area created with ID: {}", savedArea.getId());
return convertToDTO(savedArea);
}
@Override
public DeliveryAreaDTO getDeliveryAreaById(Long id) {
log.info("Getting delivery area by ID: {}", id);
DeliveryArea deliveryArea = deliveryAreaRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery area not found with id: " + id));
DeliveryAreaDTO dto = convertToDTO(deliveryArea);
if (deliveryArea.getLevel() != null && deliveryArea.getLevel() < 3) {
List<DeliveryArea> children = deliveryAreaRepository.findByParentId(deliveryArea.getId());
if (!children.isEmpty()) {
dto.setChildren(children.stream()
.map(this::convertToDTO)
.collect(Collectors.toList()));
}
}
return dto;
}
@Override
public DeliveryAreaDTO getDeliveryAreaByAreaCode(String areaCode) {
log.info("Getting delivery area by area code: {}", areaCode);
DeliveryArea deliveryArea = deliveryAreaRepository.findByAreaCode(areaCode)
.orElseThrow(() -> new ResourceNotFoundException("Delivery area not found with area code: " + areaCode));
return convertToDTO(deliveryArea);
}
@Override
@Transactional
public DeliveryAreaDTO updateDeliveryArea(Long id, DeliveryAreaUpdateRequest request) {
log.info("Updating delivery area with ID: {}", id);
DeliveryArea deliveryArea = deliveryAreaRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery area not found with id: " + id));
if (request.getName() != null) {
deliveryArea.setName(request.getName());
}
if (request.getParentId() != null) {
deliveryArea.setParentId(request.getParentId());
}
if (request.getLevel() != null) {
deliveryArea.setLevel(request.getLevel());
}
if (request.getBoundary() != null) {
deliveryArea.setBoundary(request.getBoundary());
}
if (request.getCenterLongitude() != null) {
deliveryArea.setCenterLongitude(request.getCenterLongitude());
}
if (request.getCenterLatitude() != null) {
deliveryArea.setCenterLatitude(request.getCenterLatitude());
}
if (request.getDeliveryFee() != null) {
deliveryArea.setDeliveryFee(request.getDeliveryFee());
}
if (request.getEstimatedDeliveryTime() != null) {
deliveryArea.setEstimatedDeliveryTime(request.getEstimatedDeliveryTime());
}
if (request.getStatus() != null) {
deliveryArea.setStatus(request.getStatus());
}
if (request.getDescription() != null) {
deliveryArea.setDescription(request.getDescription());
}
if (request.getRemark() != null) {
deliveryArea.setRemark(request.getRemark());
}
deliveryArea.setUpdatedTime(LocalDateTime.now());
DeliveryArea updatedArea = deliveryAreaRepository.save(deliveryArea);
log.info("Delivery area updated with ID: {}", updatedArea.getId());
return convertToDTO(updatedArea);
}
@Override
@Transactional
public void deleteDeliveryArea(Long id) {
log.info("Deleting delivery area with ID: {}", id);
DeliveryArea deliveryArea = deliveryAreaRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery area not found with id: " + id));
long childCount = deliveryAreaRepository.countByParentId(id);
if (childCount > 0) {
throw new IllegalStateException("Cannot delete area with children. Please delete children first.");
}
deliveryAreaRepository.deleteById(id);
log.info("Delivery area deleted with ID: {}", id);
}
@Override
public Page<DeliveryAreaDTO> getDeliveryAreas(Pageable pageable) {
log.info("Getting delivery areas with pagination: {}", pageable);
Page<DeliveryArea> areaPage = deliveryAreaRepository.findAll(pageable);
List<DeliveryAreaDTO> areaDTOs = areaPage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(areaDTOs, pageable, areaPage.getTotalElements());
}
@Override
public Page<DeliveryAreaDTO> getDeliveryAreasByName(String name, Pageable pageable) {
log.info("Getting delivery areas by name: {} with pagination: {}", name, pageable);
Page<DeliveryArea> areaPage = deliveryAreaRepository.findByNameContaining(name, pageable);
List<DeliveryAreaDTO> areaDTOs = areaPage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(areaDTOs, pageable, areaPage.getTotalElements());
}
@Override
public Page<DeliveryAreaDTO> getDeliveryAreasByStatus(Integer status, Pageable pageable) {
log.info("Getting delivery areas by status: {} with pagination: {}", status, pageable);
Page<DeliveryArea> areaPage = deliveryAreaRepository.findByStatus(status, pageable);
List<DeliveryAreaDTO> areaDTOs = areaPage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(areaDTOs, pageable, areaPage.getTotalElements());
}
@Override
public List<DeliveryAreaDTO> getDeliveryAreasByLevel(Integer level) {
log.info("Getting delivery areas by level: {}", level);
List<DeliveryArea> areas = deliveryAreaRepository.findByLevel(level);
return areas.stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
public List<DeliveryAreaDTO> getDeliveryAreasByParentId(Long parentId) {
log.info("Getting delivery areas by parent ID: {}", parentId);
List<DeliveryArea> areas = deliveryAreaRepository.findByParentId(parentId);
return areas.stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
public List<DeliveryAreaDTO> getDeliveryAreaTree() {
log.info("Getting delivery area tree");
List<DeliveryArea> topAreas = deliveryAreaRepository.findByLevel(1);
List<DeliveryAreaDTO> result = new ArrayList<>();
for (DeliveryArea topArea : topAreas) {
DeliveryAreaDTO topDto = convertToDTO(topArea);
List<DeliveryArea> secondLevelAreas = deliveryAreaRepository.findByParentId(topArea.getId());
List<DeliveryAreaDTO> secondLevelDtos = new ArrayList<>();
for (DeliveryArea secondArea : secondLevelAreas) {
DeliveryAreaDTO secondDto = convertToDTO(secondArea);
List<DeliveryArea> thirdLevelAreas = deliveryAreaRepository.findByParentId(secondArea.getId());
List<DeliveryAreaDTO> thirdLevelDtos = thirdLevelAreas.stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
secondDto.setChildren(thirdLevelDtos);
secondLevelDtos.add(secondDto);
}
topDto.setChildren(secondLevelDtos);
result.add(topDto);
}
return result;
}
@Override
@Transactional
public DeliveryAreaDTO updateAreaStatus(Long id, Integer status) {
log.info("Updating delivery area status with ID: {}, status: {}", id, status);
DeliveryArea deliveryArea = deliveryAreaRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery area not found with id: " + id));
deliveryArea.setStatus(status);
deliveryArea.setUpdatedTime(LocalDateTime.now());
DeliveryArea updatedArea = deliveryAreaRepository.save(deliveryArea);
log.info("Delivery area status updated with ID: {}, status: {}", updatedArea.getId(), updatedArea.getStatus());
return convertToDTO(updatedArea);
}
@Override
public Map<String, Long> countDeliveryAreas(Map<String, Object> params) {
log.info("Counting delivery areas with params: {}", params);
Map<String, Long> result = Map.of(
"total", deliveryAreaRepository.count(),
"active", deliveryAreaRepository.countByStatus(1),
"inactive", deliveryAreaRepository.countByStatus(0),
"level1", deliveryAreaRepository.countByLevel(1),
"level2", deliveryAreaRepository.countByLevel(2),
"level3", deliveryAreaRepository.countByLevel(3)
);
return result;
}
private DeliveryAreaDTO convertToDTO(DeliveryArea deliveryArea) {
DeliveryAreaDTO dto = new DeliveryAreaDTO();
BeanUtils.copyProperties(deliveryArea, dto);
if (deliveryArea.getStatus() != null) {
switch (deliveryArea.getStatus()) {
case 0:
dto.setStatusDesc("停用");
break;
case 1:
dto.setStatusDesc("启用");
break;
default:
dto.setStatusDesc("未知状态");
}
}
if (deliveryArea.getLevel() != null) {
switch (deliveryArea.getLevel()) {
case 1:
dto.setLevelDesc("校区");
break;
case 2:
dto.setLevelDesc("楼栋");
break;
case 3:
dto.setLevelDesc("具体位置");
break;
default:
dto.setLevelDesc("未知级别");
}
}
if (deliveryArea.getParentId() != null) {
deliveryAreaRepository.findById(deliveryArea.getParentId())
.ifPresent(parent -> dto.setParentName(parent.getName()));
}
return dto;
}
}
express-service\src\main\java\com\campus\express\service\impl\DeliveryRouteServiceImpl.java
package com.campus.express.service.impl;
import com.campus.express.dto.DeliveryRouteCreateRequest;
import com.campus.express.dto.DeliveryRouteDTO;
import com.campus.express.dto.DeliveryRouteUpdateRequest;
import com.campus.express.exception.ResourceNotFoundException;
import com.campus.express.model.DeliveryRoute;
import com.campus.express.repository.DeliveryRouteRepository;
import com.campus.express.service.DeliveryRouteService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Slf4j
public class DeliveryRouteServiceImpl implements DeliveryRouteService {
private final DeliveryRouteRepository deliveryRouteRepository;
private final ObjectMapper objectMapper;
@Override
@Transactional
public DeliveryRouteDTO createDeliveryRoute(DeliveryRouteCreateRequest request) {
log.info("Creating delivery route with name: {}", request.getName());
DeliveryRoute deliveryRoute = new DeliveryRoute();
BeanUtils.copyProperties(request, deliveryRoute);
if (deliveryRoute.getStatus() == null) {
deliveryRoute.setStatus(1);
}
deliveryRoute.setCreatedTime(LocalDateTime.now());
deliveryRoute.setUpdatedTime(LocalDateTime.now());
if (request.getWaypoints() != null && !request.getWaypoints().isEmpty()) {
try {
deliveryRoute.setWaypoints(objectMapper.writeValueAsString(request.getWaypoints()));
} catch (JsonProcessingException e) {
log.error("Failed to serialize waypoints", e);
deliveryRoute.setWaypoints("[]");
}
} else {
deliveryRoute.setWaypoints("[]");
}
DeliveryRoute savedRoute = deliveryRouteRepository.save(deliveryRoute);
log.info("Delivery route created with ID: {}", savedRoute.getId());
return convertToDTO(savedRoute);
}
@Override
public DeliveryRouteDTO getDeliveryRouteById(Long id) {
log.info("Getting delivery route by ID: {}", id);
DeliveryRoute deliveryRoute = deliveryRouteRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery route not found with id: " + id));
return convertToDTO(deliveryRoute);
}
@Override
public DeliveryRouteDTO getDeliveryRouteByRouteNumber(String routeNumber) {
log.info("Getting delivery route by route number: {}", routeNumber);
DeliveryRoute deliveryRoute = deliveryRouteRepository.findByRouteNumber(routeNumber)
.orElseThrow(() -> new ResourceNotFoundException("Delivery route not found with route number: " + routeNumber));
return convertToDTO(deliveryRoute);
}
@Override
@Transactional
public DeliveryRouteDTO updateDeliveryRoute(Long id, DeliveryRouteUpdateRequest request) {
log.info("Updating delivery route with ID: {}", id);
DeliveryRoute deliveryRoute = deliveryRouteRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery route not found with id: " + id));
if (request.getName() != null) {
deliveryRoute.setName(request.getName());
}
if (request.getStartPoint() != null) {
deliveryRoute.setStartPoint(request.getStartPoint());
}
if (request.getStartLongitude() != null) {
deliveryRoute.setStartLongitude(request.getStartLongitude());
}
if (request.getStartLatitude() != null) {
deliveryRoute.setStartLatitude(request.getStartLatitude());
}
if (request.getEndPoint() != null) {
deliveryRoute.setEndPoint(request.getEndPoint());
}
if (request.getEndLongitude() != null) {
deliveryRoute.setEndLongitude(request.getEndLongitude());
}
if (request.getEndLatitude() != null) {
deliveryRoute.setEndLatitude(request.getEndLatitude());
}
if (request.getWaypoints() != null) {
try {
deliveryRoute.setWaypoints(objectMapper.writeValueAsString(request.getWaypoints()));
} catch (JsonProcessingException e) {
log.error("Failed to serialize waypoints", e);
}
}
if (request.getArea() != null) {
deliveryRoute.setArea(request.getArea());
}
if (request.getAreaCode() != null) {
deliveryRoute.setAreaCode(request.getAreaCode());
}
if (request.getDistance() != null) {
deliveryRoute.setDistance(request.getDistance());
}
if (request.getEstimatedDuration() != null) {
deliveryRoute.setEstimatedDuration(request.getEstimatedDuration());
}
if (request.getCourierId() != null) {
deliveryRoute.setCourierId(request.getCourierId());
}
if (request.getCourierName() != null) {
deliveryRoute.setCourierName(request.getCourierName());
}
if (request.getStatus() != null) {
deliveryRoute.setStatus(request.getStatus());
}
if (request.getDescription() != null) {
deliveryRoute.setDescription(request.getDescription());
}
if (request.getRouteType() != null) {
deliveryRoute.setRouteType(request.getRouteType());
}
if (request.getRemark() != null) {
deliveryRoute.setRemark(request.getRemark());
}
deliveryRoute.setUpdatedTime(LocalDateTime.now());
DeliveryRoute updatedRoute = deliveryRouteRepository.save(deliveryRoute);
log.info("Delivery route updated with ID: {}", updatedRoute.getId());
return convertToDTO(updatedRoute);
}
@Override
@Transactional
public void deleteDeliveryRoute(Long id) {
log.info("Deleting delivery route with ID: {}", id);
if (!deliveryRouteRepository.existsById(id)) {
throw new ResourceNotFoundException("Delivery route not found with id: " + id);
}
deliveryRouteRepository.deleteById(id);
log.info("Delivery route deleted with ID: {}", id);
}
@Override
public Page<DeliveryRouteDTO> getDeliveryRoutes(Pageable pageable) {
log.info("Getting delivery routes with pagination: {}", pageable);
Page<DeliveryRoute> routePage = deliveryRouteRepository.findAll(pageable);
List<DeliveryRouteDTO> routeDTOs = routePage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(routeDTOs, pageable, routePage.getTotalElements());
}
@Override
public Page<DeliveryRouteDTO> getDeliveryRoutesByName(String name, Pageable pageable) {
log.info("Getting delivery routes by name: {} with pagination: {}", name, pageable);
Page<DeliveryRoute> routePage = deliveryRouteRepository.findByNameContaining(name, pageable);
List<DeliveryRouteDTO> routeDTOs = routePage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(routeDTOs, pageable, routePage.getTotalElements());
}
@Override
public Page<DeliveryRouteDTO> getDeliveryRoutesByStatus(Integer status, Pageable pageable) {
log.info("Getting delivery routes by status: {} with pagination: {}", status, pageable);
Page<DeliveryRoute> routePage = deliveryRouteRepository.findByStatus(status, pageable);
List<DeliveryRouteDTO> routeDTOs = routePage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(routeDTOs, pageable, routePage.getTotalElements());
}
@Override
public List<DeliveryRouteDTO> getDeliveryRoutesByArea(String area) {
log.info("Getting delivery routes by area: {}", area);
List<DeliveryRoute> routes = deliveryRouteRepository.findByArea(area);
return routes.stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
public List<DeliveryRouteDTO> getDeliveryRoutesByCourierId(Long courierId) {
log.info("Getting delivery routes by courier ID: {}", courierId);
List<DeliveryRoute> routes = deliveryRouteRepository.findByCourierId(courierId);
return routes.stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
@Transactional
public DeliveryRouteDTO assignCourier(Long id, Long courierId, String courierName) {
log.info("Assigning courier to delivery route with ID: {}, courier ID: {}", id, courierId);
DeliveryRoute deliveryRoute = deliveryRouteRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery route not found with id: " + id));
deliveryRoute.setCourierId(courierId);
deliveryRoute.setCourierName(courierName);
deliveryRoute.setUpdatedTime(LocalDateTime.now());
DeliveryRoute updatedRoute = deliveryRouteRepository.save(deliveryRoute);
log.info("Courier assigned to delivery route with ID: {}", updatedRoute.getId());
return convertToDTO(updatedRoute);
}
@Override
@Transactional
public DeliveryRouteDTO updateRouteStatus(Long id, Integer status) {
log.info("Updating delivery route status with ID: {}, status: {}", id, status);
DeliveryRoute deliveryRoute = deliveryRouteRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery route not found with id: " + id));
deliveryRoute.setStatus(status);
deliveryRoute.setUpdatedTime(LocalDateTime.now());
DeliveryRoute updatedRoute = deliveryRouteRepository.save(deliveryRoute);
log.info("Delivery route status updated with ID: {}, status: {}", updatedRoute.getId(), updatedRoute.getStatus());
return convertToDTO(updatedRoute);
}
@Override
public Map<String, Long> countDeliveryRoutes(Map<String, Object> params) {
log.info("Counting delivery routes with params: {}", params);
Map<String, Long> result = Map.of(
"total", deliveryRouteRepository.count(),
"active", deliveryRouteRepository.countByStatus(1),
"inactive", deliveryRouteRepository.countByStatus(0)
);
return result;
}
private DeliveryRouteDTO convertToDTO(DeliveryRoute deliveryRoute) {
DeliveryRouteDTO dto = new DeliveryRouteDTO();
BeanUtils.copyProperties(deliveryRoute, dto);
List<DeliveryRouteDTO.WaypointDTO> waypoints = new ArrayList<>();
if (deliveryRoute.getWaypoints() != null && !deliveryRoute.getWaypoints().isEmpty()) {
try {
waypoints = objectMapper.readValue(
deliveryRoute.getWaypoints(),
objectMapper.getTypeFactory().constructCollectionType(
List.class, DeliveryRouteDTO.WaypointDTO.class)
);
} catch (JsonProcessingException e) {
log.error("Failed to deserialize waypoints", e);
}
}
dto.setWaypoints(waypoints);
if (deliveryRoute.getStatus() != null) {
switch (deliveryRoute.getStatus()) {
case 0:
dto.setStatusDesc("停用");
break;
case 1:
dto.setStatusDesc("启用");
break;
default:
dto.setStatusDesc("未知状态");
}
}
if (deliveryRoute.getRouteType() != null) {
switch (deliveryRoute.getRouteType()) {
case 0:
dto.setRouteTypeDesc("步行");
break;
case 1:
dto.setRouteTypeDesc("自行车");
break;
case 2:
dto.setRouteTypeDesc("电动车");
break;
case 3:
dto.setRouteTypeDesc("汽车");
break;
default:
dto.setRouteTypeDesc("未知类型");
}
}
return dto;
}
}
express-service\src\main\java\com\campus\express\service\impl\DeliveryServiceImpl.java
package com.campus.express.service.impl;
import com.campus.express.dto.DeliveryCreateRequest;
import com.campus.express.dto.DeliveryDTO;
import com.campus.express.dto.DeliveryUpdateRequest;
import com.campus.express.exception.ResourceNotFoundException;
import com.campus.express.model.Delivery;
import com.campus.express.repository.DeliveryRepository;
import com.campus.express.service.DeliveryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Slf4j
public class DeliveryServiceImpl implements DeliveryService {
private final DeliveryRepository deliveryRepository;
private final Random random = new Random();
@Override
@Transactional
public DeliveryDTO createDelivery(DeliveryCreateRequest request) {
log.info("Creating delivery task for express ID: {}", request.getExpressId());
Delivery delivery = new Delivery();
BeanUtils.copyProperties(request, delivery);
delivery.setStatus(0);
delivery.setCreatedTime(LocalDateTime.now());
delivery.setUpdatedTime(LocalDateTime.now());
if (delivery.getPriority() == null) {
delivery.setPriority(0);
}
delivery.setDeliveryCode(generateDeliveryCode());
Delivery savedDelivery = deliveryRepository.save(delivery);
log.info("Delivery task created with ID: {}", savedDelivery.getId());
return convertToDTO(savedDelivery);
}
@Override
public DeliveryDTO getDeliveryById(Long id) {
log.info("Getting delivery task by ID: {}", id);
Delivery delivery = deliveryRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery not found with id: " + id));
return convertToDTO(delivery);
}
@Override
public DeliveryDTO getDeliveryByExpressId(Long expressId) {
log.info("Getting delivery task by express ID: {}", expressId);
Delivery delivery = deliveryRepository.findByExpressId(expressId)
.orElseThrow(() -> new ResourceNotFoundException("Delivery not found with express id: " + expressId));
return convertToDTO(delivery);
}
@Override
@Transactional
public DeliveryDTO updateDelivery(Long id, DeliveryUpdateRequest request) {
log.info("Updating delivery task with ID: {}", id);
Delivery delivery = deliveryRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery not found with id: " + id));
if (request.getCourierId() != null) {
delivery.setCourierId(request.getCourierId());
}
if (request.getCourierName() != null) {
delivery.setCourierName(request.getCourierName());
}
if (request.getCourierPhone() != null) {
delivery.setCourierPhone(request.getCourierPhone());
}
if (request.getRecipientName() != null) {
delivery.setRecipientName(request.getRecipientName());
}
if (request.getRecipientPhone() != null) {
delivery.setRecipientPhone(request.getRecipientPhone());
}
if (request.getRecipientAddress() != null) {
delivery.setRecipientAddress(request.getRecipientAddress());
}
if (request.getDeliveryArea() != null) {
delivery.setDeliveryArea(request.getDeliveryArea());
}
if (request.getAreaCode() != null) {
delivery.setAreaCode(request.getAreaCode());
}
if (request.getRouteId() != null) {
delivery.setRouteId(request.getRouteId());
}
if (request.getRouteName() != null) {
delivery.setRouteName(request.getRouteName());
}
if (request.getPlannedDeliveryTime() != null) {
delivery.setPlannedDeliveryTime(request.getPlannedDeliveryTime());
}
if (request.getActualDeliveryTime() != null) {
delivery.setActualDeliveryTime(request.getActualDeliveryTime());
}
if (request.getCompletedTime() != null) {
delivery.setCompletedTime(request.getCompletedTime());
}
if (request.getDeliveryCode() != null) {
delivery.setDeliveryCode(request.getDeliveryCode());
}
if (request.getStatus() != null) {
delivery.setStatus(request.getStatus());
}
if (request.getPriority() != null) {
delivery.setPriority(request.getPriority());
}
if (request.getDeliveryFee() != null) {
delivery.setDeliveryFee(request.getDeliveryFee());
}
if (request.getDistance() != null) {
delivery.setDistance(request.getDistance());
}
if (request.getEstimatedDuration() != null) {
delivery.setEstimatedDuration(request.getEstimatedDuration());
}
if (request.getActualDuration() != null) {
delivery.setActualDuration(request.getActualDuration());
}
if (request.getCancelReason() != null) {
delivery.setCancelReason(request.getCancelReason());
}
if (request.getRemark() != null) {
delivery.setRemark(request.getRemark());
}
delivery.setUpdatedTime(LocalDateTime.now());
Delivery updatedDelivery = deliveryRepository.save(delivery);
log.info("Delivery task updated with ID: {}", updatedDelivery.getId());
return convertToDTO(updatedDelivery);
}
@Override
@Transactional
public void deleteDelivery(Long id) {
log.info("Deleting delivery task with ID: {}", id);
if (!deliveryRepository.existsById(id)) {
throw new ResourceNotFoundException("Delivery not found with id: " + id);
}
deliveryRepository.deleteById(id);
log.info("Delivery task deleted with ID: {}", id);
}
@Override
public Page<DeliveryDTO> getDeliveries(Pageable pageable) {
log.info("Getting delivery tasks with pagination: {}", pageable);
Page<Delivery> deliveryPage = deliveryRepository.findAll(pageable);
List<DeliveryDTO> deliveryDTOs = deliveryPage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(deliveryDTOs, pageable, deliveryPage.getTotalElements());
}
@Override
public Page<DeliveryDTO> getDeliveriesByStatus(Integer status, Pageable pageable) {
log.info("Getting delivery tasks by status: {} with pagination: {}", status, pageable);
Page<Delivery> deliveryPage = deliveryRepository.findByStatus(status, pageable);
List<DeliveryDTO> deliveryDTOs = deliveryPage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(deliveryDTOs, pageable, deliveryPage.getTotalElements());
}
@Override
public Page<DeliveryDTO> getDeliveriesByCourierId(Long courierId, Pageable pageable) {
log.info("Getting delivery tasks by courier ID: {} with pagination: {}", courierId, pageable);
Page<Delivery> deliveryPage = deliveryRepository.findByCourierId(courierId, pageable);
List<DeliveryDTO> deliveryDTOs = deliveryPage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(deliveryDTOs, pageable, deliveryPage.getTotalElements());
}
@Override
public Page<DeliveryDTO> getDeliveriesByArea(String area, Pageable pageable) {
log.info("Getting delivery tasks by area: {} with pagination: {}", area, pageable);
Page<Delivery> deliveryPage = deliveryRepository.findByDeliveryAreaContaining(area, pageable);
List<DeliveryDTO> deliveryDTOs = deliveryPage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(deliveryDTOs, pageable, deliveryPage.getTotalElements());
}
@Override
public Page<DeliveryDTO> getDeliveriesByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable) {
log.info("Getting delivery tasks by created time between: {} and {} with pagination: {}", startTime, endTime, pageable);
Page<Delivery> deliveryPage = deliveryRepository.findByCreatedTimeBetween(startTime, endTime, pageable);
List<DeliveryDTO> deliveryDTOs = deliveryPage.getContent().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return new PageImpl<>(deliveryDTOs, pageable, deliveryPage.getTotalElements());
}
@Override
@Transactional
public DeliveryDTO assignCourier(Long id, Long courierId, String courierName, String courierPhone) {
log.info("Assigning courier to delivery task with ID: {}, courier ID: {}", id, courierId);
Delivery delivery = deliveryRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery not found with id: " + id));
delivery.setCourierId(courierId);
delivery.setCourierName(courierName);
delivery.setCourierPhone(courierPhone);
delivery.setStatus(1);
delivery.setUpdatedTime(LocalDateTime.now());
Delivery updatedDelivery = deliveryRepository.save(delivery);
log.info("Courier assigned to delivery task with ID: {}", updatedDelivery.getId());
return convertToDTO(updatedDelivery);
}
@Override
@Transactional
public DeliveryDTO updateDeliveryStatus(Long id, Integer status) {
log.info("Updating delivery task status with ID: {}, status: {}", id, status);
Delivery delivery = deliveryRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery not found with id: " + id));
delivery.setStatus(status);
delivery.setUpdatedTime(LocalDateTime.now());
if (status == 2) {
delivery.setActualDeliveryTime(LocalDateTime.now());
} else if (status == 4) {
delivery.setCompletedTime(LocalDateTime.now());
if (delivery.getActualDeliveryTime() != null) {
long minutes = java.time.Duration.between(delivery.getActualDeliveryTime(), LocalDateTime.now()).toMinutes();
delivery.setActualDuration((int) minutes);
}
}
Delivery updatedDelivery = deliveryRepository.save(delivery);
log.info("Delivery task status updated with ID: {}, status: {}", updatedDelivery.getId(), updatedDelivery.getStatus());
return convertToDTO(updatedDelivery);
}
@Override
@Transactional
public DeliveryDTO cancelDelivery(Long id, String reason) {
log.info("Cancelling delivery task with ID: {}, reason: {}", id, reason);
Delivery delivery = deliveryRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery not found with id: " + id));
delivery.setStatus(5);
delivery.setCancelReason(reason);
delivery.setUpdatedTime(LocalDateTime.now());
Delivery updatedDelivery = deliveryRepository.save(delivery);
log.info("Delivery task cancelled with ID: {}", updatedDelivery.getId());
return convertToDTO(updatedDelivery);
}
@Override
public String generateDeliveryCode() {
StringBuilder code = new StringBuilder();
for (int i = 0; i < 6; i++) {
code.append(random.nextInt(10));
}
return code.toString();
}
@Override
public boolean verifyDeliveryCode(Long id, String code) {
log.info("Verifying delivery code for delivery task with ID: {}", id);
Delivery delivery = deliveryRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Delivery not found with id: " + id));
return delivery.getDeliveryCode().equals(code);
}
@Override
public Map<String, Long> countDeliveries(Map<String, Object> params) {
log.info("Counting delivery tasks with params: {}", params);
Map<String, Long> result = Map.of(
"total", deliveryRepository.count(),
"pending", deliveryRepository.countByStatus(0),
"assigned", deliveryRepository.countByStatus(1),
"delivering", deliveryRepository.countByStatus(2),
"delivered", deliveryRepository.countByStatus(3),
"completed", deliveryRepository.countByStatus(4),
"cancelled", deliveryRepository.countByStatus(5)
);
return result;
}
private DeliveryDTO convertToDTO(Delivery delivery) {
DeliveryDTO dto = new DeliveryDTO();
BeanUtils.copyProperties(delivery, dto);
switch (delivery.getStatus()) {
case 0:
dto.setStatusDesc("待分配");
break;
case 1:
dto.setStatusDesc("待配送");
break;
case 2:
dto.setStatusDesc("配送中");
break;
case 3:
dto.setStatusDesc("已送达");
break;
case 4:
dto.setStatusDesc("已完成");
break;
case 5:
dto.setStatusDesc("已取消");
break;
default:
dto.setStatusDesc("未知状态");
}
switch (delivery.getPriority()) {
case 0:
dto.setPriorityDesc("普通");
break;
case 1:
dto.setPriorityDesc("优先");
break;
case 2:
dto.setPriorityDesc("加急");
break;
default:
dto.setPriorityDesc("未知优先级");
}
return dto;
}
}
express-service\src\main\java\com\campus\express\service\impl\ExpressServiceImpl.java
package com.campus.express.service.impl;
import com.campus.express.dto.ExpressCreateRequest;
import com.campus.express.dto.ExpressDTO;
import com.campus.express.dto.ExpressUpdateRequest;
import com.campus.express.exception.ResourceNotFoundException;
import com.campus.express.model.Express;
import com.campus.express.repository.ExpressRepository;
import com.campus.express.service.ExpressService;
import com.campus.express.service.ExpressTrackingService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Random;
@Service
@RequiredArgsConstructor
public class ExpressServiceImpl implements ExpressService {
private final ExpressRepository expressRepository;
private final ExpressTrackingService expressTrackingService;
private static final Random random = new Random();
@Override
@Transactional
public ExpressDTO createExpress(ExpressCreateRequest request) {
Express express = Express.builder()
.trackingNumber(request.getTrackingNumber())
.company(request.getCompany())
.recipientName(request.getRecipientName())
.recipientPhone(request.getRecipientPhone())
.recipientAddress(request.getRecipientAddress())
.description(request.getDescription())
.weight(request.getWeight())
.status(0)
.courierId(request.getCourierId())
.courierName(request.getCourierName())
.courierPhone(request.getCourierPhone())
.userId(request.getUserId())
.remark(request.getRemark())
.build();
Express savedExpress = expressRepository.save(express);
expressTrackingService.createTracking(
savedExpress.getId(),
savedExpress.getTrackingNumber(),
0,
"快递已创建",
null,
0,
"系统",
null,
null
);
return convertToDTO(savedExpress);
}
@Override
public ExpressDTO getExpressById(Long id) {
Express express = expressRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("快递不存在,ID: " + id));
return convertToDTO(express);
}
@Override
public ExpressDTO getExpressByTrackingNumber(String trackingNumber) {
Express express = expressRepository.findByTrackingNumber(trackingNumber)
.orElseThrow(() -> new ResourceNotFoundException("快递不存在,单号: " + trackingNumber));
return convertToDTO(express);
}
@Override
@Transactional
public ExpressDTO updateExpress(Long id, ExpressUpdateRequest request) {
Express express = expressRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("快递不存在,ID: " + id));
if (request.getCompany() != null) {
express.setCompany(request.getCompany());
}
if (request.getRecipientName() != null) {
express.setRecipientName(request.getRecipientName());
}
if (request.getRecipientPhone() != null) {
express.setRecipientPhone(request.getRecipientPhone());
}
if (request.getRecipientAddress() != null) {
express.setRecipientAddress(request.getRecipientAddress());
}
if (request.getDescription() != null) {
express.setDescription(request.getDescription());
}
if (request.getWeight() != null) {
express.setWeight(request.getWeight());
}
if (request.getStatus() != null) {
express.setStatus(request.getStatus());
}
if (request.getCourierId() != null) {
express.setCourierId(request.getCourierId());
express.setCourierName(request.getCourierName());
express.setCourierPhone(request.getCourierPhone());
}
if (request.getUserId() != null) {
express.setUserId(request.getUserId());
}
if (request.getCabinetId() != null) {
express.setCabinetId(request.getCabinetId());
}
if (request.getCabinetCell() != null) {
express.setCabinetCell(request.getCabinetCell());
}
if (request.getPickupCode() != null) {
express.setPickupCode(request.getPickupCode());
}
if (request.getRemark() != null) {
express.setRemark(request.getRemark());
}
Express updatedExpress = expressRepository.save(express);
return convertToDTO(updatedExpress);
}
@Override
@Transactional
public void deleteExpress(Long id) {
if (!expressRepository.existsById(id)) {
throw new ResourceNotFoundException("快递不存在,ID: " + id);
}
expressRepository.deleteById(id);
}
@Override
public Page<ExpressDTO> getAllExpress(Pageable pageable) {
return expressRepository.findAll(pageable).map(this::convertToDTO);
}
@Override
public Page<ExpressDTO> getExpressByUserId(Long userId, Pageable pageable) {
return expressRepository.findByUserId(userId, pageable).map(this::convertToDTO);
}
@Override
public Page<ExpressDTO> getExpressByCourierId(Long courierId, Pageable pageable) {
return expressRepository.findByCourierId(courierId, pageable).map(this::convertToDTO);
}
@Override
public Page<ExpressDTO> getExpressByCabinetId(Long cabinetId, Pageable pageable) {
return expressRepository.findByCabinetId(cabinetId, pageable).map(this::convertToDTO);
}
@Override
public Page<ExpressDTO> getExpressByStatus(Integer status, Pageable pageable) {
return expressRepository.findByStatus(status, pageable).map(this::convertToDTO);
}
@Override
public Page<ExpressDTO> searchExpressByRecipient(String keyword, Pageable pageable) {
return expressRepository.findByRecipientNameOrPhoneContaining(keyword, pageable).map(this::convertToDTO);
}
@Override
@Transactional
public ExpressDTO assignCourier(Long expressId, Long courierId, String courierName, String courierPhone) {
Express express = expressRepository.findById(expressId)
.orElseThrow(() -> new ResourceNotFoundException("快递不存在,ID: " + expressId));
express.setCourierId(courierId);
express.setCourierName(courierName);
express.setCourierPhone(courierPhone);
expressTrackingService.createTracking(
express.getId(),
express.getTrackingNumber(),
1,
"快递已分配给快递员: " + courierName,
courierId,
1,
courierName,
null,
null
);
Express updatedExpress = expressRepository.save(express);
return convertToDTO(updatedExpress);
}
@Override
@Transactional
public ExpressDTO assignCabinet(Long expressId, Long cabinetId, String cellNumber) {
Express express = expressRepository.findById(expressId)
.orElseThrow(() -> new ResourceNotFoundException("快递不存在,ID: " + expressId));
express.setCabinetId(cabinetId);
express.setCabinetCell(cellNumber);
express.setPickupCode(generatePickupCode(expressId));
express.setStatus(3);
express.setDeliveryTime(LocalDateTime.now());
expressTrackingService.createTracking(
express.getId(),
express.getTrackingNumber(),
3,
"快递已存入柜子,取件码: " + express.getPickupCode(),
express.getCourierId(),
1,
express.getCourierName(),
null,
null
);
Express updatedExpress = expressRepository.save(express);
return convertToDTO(updatedExpress);
}
@Override
@Transactional
public ExpressDTO updateExpressStatus(Long expressId, Integer status, Long operatorId, Integer operatorType, String operatorName, String description) {
Express express = expressRepository.findById(expressId)
.orElseThrow(() -> new ResourceNotFoundException("快递不存在,ID: " + expressId));
express.setStatus(status);
if (status == 1) {
express.setCollectionTime(LocalDateTime.now());
} else if (status == 3) {
express.setDeliveryTime(LocalDateTime.now());
} else if (status == 4) {
express.setSignTime(LocalDateTime.now());
}
expressTrackingService.createTracking(
express.getId(),
express.getTrackingNumber(),
status,
description,
operatorId,
operatorType,
operatorName,
null,
null
);
Express updatedExpress = expressRepository.save(express);
return convertToDTO(updatedExpress);
}
@Override
@Transactional
public ExpressDTO signExpress(Long expressId, Long userId, String userName) {
Express express = expressRepository.findById(expressId)
.orElseThrow(() -> new ResourceNotFoundException("快递不存在,ID: " + expressId));
express.setStatus(4);
express.setSignTime(LocalDateTime.now());
expressTrackingService.createTracking(
express.getId(),
express.getTrackingNumber(),
4,
"快递已被签收",
userId,
2,
userName,
null,
null
);
Express updatedExpress = expressRepository.save(express);
return convertToDTO(updatedExpress);
}
@Override
public long countExpressByUserId(Long userId) {
return expressRepository.countByUserId(userId);
}
@Override
public long countExpressByCourierId(Long courierId) {
return expressRepository.countByCourierId(courierId);
}
@Override
public long countExpressByStatus(Integer status) {
return expressRepository.countByStatus(status);
}
@Override
public Page<ExpressDTO> getExpressByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable) {
return expressRepository.findByCreatedTimeBetween(startTime, endTime, pageable).map(this::convertToDTO);
}
@Override
public String generatePickupCode(Long expressId) {
StringBuilder code = new StringBuilder();
for (int i = 0; i < 6; i++) {
code.append(random.nextInt(10));
}
return code.toString();
}
@Override
public boolean verifyPickupCode(Long expressId, String pickupCode) {
Express express = expressRepository.findById(expressId)
.orElseThrow(() -> new ResourceNotFoundException("快递不存在,ID: " + expressId));
return express.getPickupCode() != null && express.getPickupCode().equals(pickupCode);
}
private ExpressDTO convertToDTO(Express express) {
return ExpressDTO.builder()
.id(express.getId())
.trackingNumber(express.getTrackingNumber())
.company(express.getCompany())
.recipientName(express.getRecipientName())
.recipientPhone(express.getRecipientPhone())
.recipientAddress(express.getRecipientAddress())
.description(express.getDescription())
.weight(express.getWeight())
.status(express.getStatus())
.statusDesc(getStatusDesc(express.getStatus()))
.courierId(express.getCourierId())
.courierName(express.getCourierName())
.courierPhone(express.getCourierPhone())
.userId(express.getUserId())
.cabinetId(express.getCabinetId())
.cabinetName(express.getCabinetName())
.cabinetLocation(express.getCabinetLocation())
.cabinetCell(express.getCabinetCell())
.pickupCode(express.getPickupCode())
.collectionTime(express.getCollectionTime())
.deliveryTime(express.getDeliveryTime())
.signTime(express.getSignTime())
.remark(express.getRemark())
.createdTime(express.getCreatedTime())
.updatedTime(express.getUpdatedTime())
.build();
}
private String getStatusDesc(Integer status) {
if (status == null) {
return null;
}
switch (status) {
case 0:
return "待揽收";
case 1:
return "已揽收";
case 2:
return "配送中";
case 3:
return "已送达";
case 4:
return "已签收";
case 5:
return "异常";
default:
return "未知状态";
}
}
}
express-service\src\main\java\com\campus\express\service\impl\ExpressTrackingServiceImpl.java
package com.campus.express.service.impl;
import com.campus.express.dto.ExpressTrackingDTO;
import com.campus.express.exception.ResourceNotFoundException;
import com.campus.express.model.ExpressTracking;
import com.campus.express.repository.ExpressTrackingRepository;
import com.campus.express.service.ExpressTrackingService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class ExpressTrackingServiceImpl implements ExpressTrackingService {
private final ExpressTrackingRepository expressTrackingRepository;
@Override
@Transactional
public ExpressTrackingDTO createTracking(Long expressId, String trackingNumber, Integer operationType,
String description, Long operatorId, Integer operatorType,
String operatorName, String location, String remark) {
ExpressTracking tracking = ExpressTracking.builder()
.expressId(expressId)
.trackingNumber(trackingNumber)
.operationType(operationType)
.description(description)
.operatorId(operatorId)
.operatorType(operatorType)
.operatorName(operatorName)
.location(location)
.remark(remark)
.build();
ExpressTracking savedTracking = expressTrackingRepository.save(tracking);
return convertToDTO(savedTracking);
}
@Override
public ExpressTrackingDTO getTrackingById(Long id) {
ExpressTracking tracking = expressTrackingRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("跟踪记录不存在,ID: " + id));
return convertToDTO(tracking);
}
@Override
public List<ExpressTrackingDTO> getTrackingsByExpressId(Long expressId) {
return expressTrackingRepository.findByExpressIdOrderByCreatedTimeDesc(expressId).stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
public List<ExpressTrackingDTO> getTrackingsByTrackingNumber(String trackingNumber) {
return expressTrackingRepository.findByTrackingNumberOrderByCreatedTimeDesc(trackingNumber).stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
@Override
public Page<ExpressTrackingDTO> getTrackingsByOperationType(Integer operationType, Pageable pageable) {
return expressTrackingRepository.findByOperationType(operationType, pageable).map(this::convertToDTO);
}
@Override
public Page<ExpressTrackingDTO> getTrackingsByOperatorId(Long operatorId, Pageable pageable) {
return expressTrackingRepository.findByOperatorId(operatorId, pageable).map(this::convertToDTO);
}
@Override
public Page<ExpressTrackingDTO> getTrackingsByOperatorType(Integer operatorType, Pageable pageable) {
return expressTrackingRepository.findByOperatorType(operatorType, pageable).map(this::convertToDTO);
}
@Override
public Page<ExpressTrackingDTO> getTrackingsByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable) {
return expressTrackingRepository.findByCreatedTimeBetween(startTime, endTime, pageable).map(this::convertToDTO);
}
@Override
public long countTrackingsByExpressId(Long expressId) {
return expressTrackingRepository.countByExpressId(expressId);
}
@Override
public long countTrackingsByOperationType(Integer operationType) {
return expressTrackingRepository.countByOperationType(operationType);
}
@Override
public long countTrackingsByOperatorId(Long operatorId) {
return expressTrackingRepository.countByOperatorId(operatorId);
}
@Override
public long countTrackingsByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
return expressTrackingRepository.countByCreatedTimeBetween(startTime, endTime);
}
@Override
@Transactional
public void deleteTracking(Long id) {
if (!expressTrackingRepository.existsById(id)) {
throw new ResourceNotFoundException("跟踪记录不存在,ID: " + id);
}
expressTrackingRepository.deleteById(id);
}
private ExpressTrackingDTO convertToDTO(ExpressTracking tracking) {
return ExpressTrackingDTO.builder()
.id(tracking.getId())
.expressId(tracking.getExpressId())
.trackingNumber(tracking.getTrackingNumber())
.operationType(tracking.getOperationType())
.operationTypeDesc(getOperationTypeDesc(tracking.getOperationType()))
.description(tracking.getDescription())
.operatorId(tracking.getOperatorId())
.operatorType(tracking.getOperatorType())
.operatorTypeDesc(getOperatorTypeDesc(tracking.getOperatorType()))
.operatorName(tracking.getOperatorName())
.location(tracking.getLocation())
.remark(tracking.getRemark())
.createdTime(tracking.getCreatedTime())
.build();
}
private String getOperationTypeDesc(Integer operationType) {
if (operationType == null) {
return null;
}
switch (operationType) {
case 0:
return "创建";
case 1:
return "揽收";
case 2:
return "运输";
case 3:
return "送达";
case 4:
return "签收";
case 5:
return "异常";
default:
return "未知操作";
}
}
private String getOperatorTypeDesc(Integer operatorType) {
if (operatorType == null) {
return null;
}
switch (operatorType) {
case 0:
return "系统";
case 1:
return "快递员";
case 2:
return "用户";
case 3:
return "管理员";
default:
return "未知类型";
}
}
}
express-service\src\main\java\com\campus\express\service\impl\InAppNotificationSender.java
package com.campus.express.service.impl;
import com.campus.express.model.Notification;
import com.campus.express.service.NotificationSender;
import com.campus.express.util.NotificationUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class InAppNotificationSender implements NotificationSender {
@Override
public boolean send(Notification notification) {
if (notification == null) {
log.error("Notification is null");
return false;
}
if (notification.getChannel() != getSupportedChannel()) {
log.error("Unsupported notification channel: {}", notification.getChannel());
return false;
}
try {
log.info("Sending in-app notification: {} to receiver: {}", notification.getTitle(), notification.getReceiverId());
log.info("In-app notification sent successfully: {}", notification.getId());
return true;
} catch (Exception e) {
log.error("Failed to send in-app notification: {}", e.getMessage(), e);
return false;
}
}
@Override
public int getSupportedChannel() {
return NotificationUtils.NotificationChannel.IN_APP;
}
}
express-service\src\main\java\com\campus\express\service\impl\NotificationServiceImpl.java