|
@@ -0,0 +1,465 @@
|
|
|
+package com.example.demo.sujiajie.service.impl;
|
|
|
+
|
|
|
+
|
|
|
+import com.example.demo.sujiajie.common.constant.TravelPlanConstant;
|
|
|
+import com.example.demo.sujiajie.common.exception.TravelPlanException;
|
|
|
+import com.example.demo.sujiajie.dto.request.*;
|
|
|
+import com.example.demo.sujiajie.dto.response.TravelPlanResponse;
|
|
|
+import com.example.demo.sujiajie.dto.response.TravelPlanDetailResponse;
|
|
|
+import com.example.demo.sujiajie.entity.TravelPlan;
|
|
|
+import com.example.demo.sujiajie.entity.TravelPlanCollaborator;
|
|
|
+import com.example.demo.sujiajie.entity.TravelPlanDetail;
|
|
|
+import com.example.demo.sujiajie.entity.TravelPlanOperation;
|
|
|
+import com.example.demo.sujiajie.repository.TravelPlanCollaboratorRepository;
|
|
|
+import com.example.demo.sujiajie.repository.TravelPlanDetailRepository;
|
|
|
+import com.example.demo.sujiajie.repository.TravelPlanOperationRepository;
|
|
|
+import com.example.demo.sujiajie.repository.TravelPlanRepository;
|
|
|
+import com.example.demo.sujiajie.service.TravelPlanService;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.modelmapper.ModelMapper;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 行程服务实现类
|
|
|
+ * 实现行程管理的业务逻辑
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class TravelPlanServiceImpl implements TravelPlanService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TravelPlanRepository travelPlanRepository;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TravelPlanDetailRepository detailRepository;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TravelPlanCollaboratorRepository collaboratorRepository;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TravelPlanOperationRepository operationRepository;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ModelMapper modelMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建行程
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public TravelPlan createTravelPlan(CreateTravelPlanRequest request) {
|
|
|
+ // 创建行程实体
|
|
|
+ TravelPlan travelPlan = new TravelPlan();
|
|
|
+ travelPlan.setUserId(request.getUserId());
|
|
|
+ travelPlan.setPlanName(request.getPlanName());
|
|
|
+ travelPlan.setTotalDays(request.getTotalDays());
|
|
|
+ travelPlan.setTotalBudget(request.getTotalBudget());
|
|
|
+ travelPlan.setPreference(request.getPreference());
|
|
|
+ travelPlan.setStatus(TravelPlanConstant.Status.DRAFT);
|
|
|
+ travelPlan.setCreateTime(new Date());
|
|
|
+ travelPlan.setUpdateTime(new Date());
|
|
|
+
|
|
|
+ // 保存行程
|
|
|
+ travelPlan = travelPlanRepository.save(travelPlan);
|
|
|
+
|
|
|
+ // 记录创建操作
|
|
|
+ recordOperationInternal(travelPlan.getPlanId(), TravelPlanConstant.OperationType.SAVE,
|
|
|
+ request.getUserId(), "创建行程");
|
|
|
+
|
|
|
+ return travelPlan;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新行程
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public TravelPlan updateTravelPlan(UpdateTravelPlanRequest request) {
|
|
|
+ // 获取行程
|
|
|
+ TravelPlan travelPlan = getTravelPlanById(request.getPlanId());
|
|
|
+
|
|
|
+ // 检查权限
|
|
|
+ checkPermissionInternal(travelPlan, request.getUserId(), TravelPlanConstant.Permission.EDIT);
|
|
|
+
|
|
|
+ // 更新行程信息
|
|
|
+ if (request.getPlanName() != null) {
|
|
|
+ travelPlan.setPlanName(request.getPlanName());
|
|
|
+ }
|
|
|
+ if (request.getTotalDays() != null) {
|
|
|
+ travelPlan.setTotalDays(request.getTotalDays());
|
|
|
+ }
|
|
|
+ if (request.getTotalBudget() != null) {
|
|
|
+ travelPlan.setTotalBudget(request.getTotalBudget());
|
|
|
+ }
|
|
|
+ if (request.getPreference() != null) {
|
|
|
+ travelPlan.setPreference(request.getPreference());
|
|
|
+ }
|
|
|
+ if (request.getStatus() != null) {
|
|
|
+ travelPlan.setStatus(request.getStatus());
|
|
|
+ }
|
|
|
+
|
|
|
+ travelPlan.setUpdateTime(new Date());
|
|
|
+
|
|
|
+ // 保存更新
|
|
|
+ travelPlan = travelPlanRepository.save(travelPlan);
|
|
|
+
|
|
|
+ // 记录更新操作
|
|
|
+ recordOperationInternal(travelPlan.getPlanId(), TravelPlanConstant.OperationType.SAVE,
|
|
|
+ request.getUserId(), "更新行程");
|
|
|
+
|
|
|
+ return travelPlan;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除行程
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public void deleteTravelPlan(Long planId, String userId) {
|
|
|
+ // 获取行程
|
|
|
+ TravelPlan travelPlan = getTravelPlanById(planId);
|
|
|
+
|
|
|
+ // 检查权限(只有管理员或创建者可以删除)
|
|
|
+ if (!travelPlan.getUserId().equals(userId) &&
|
|
|
+ !checkPermissionInternal(travelPlan, userId, TravelPlanConstant.Permission.ADMIN)) {
|
|
|
+ throw new TravelPlanException("没有权限删除此行程");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 删除行程相关的所有数据
|
|
|
+ detailRepository.deleteByTravelPlanPlanId(planId);
|
|
|
+ collaboratorRepository.deleteByTravelPlanPlanId(planId);
|
|
|
+ operationRepository.deleteByTravelPlanPlanId(planId);
|
|
|
+
|
|
|
+ // 删除行程
|
|
|
+ travelPlanRepository.deleteById(planId);
|
|
|
+
|
|
|
+ // 记录删除操作
|
|
|
+ recordOperationInternal(planId, TravelPlanConstant.OperationType.OTHER,
|
|
|
+ userId, "删除行程");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取行程详情
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(readOnly = true)
|
|
|
+ public TravelPlanResponse getTravelPlanDetail(Long planId, String userId) {
|
|
|
+ // 获取行程基本信息
|
|
|
+ TravelPlan travelPlan = travelPlanRepository.findWithDetailsById(planId);
|
|
|
+
|
|
|
+ if (travelPlan == null) {
|
|
|
+ throw new TravelPlanException("行程不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查权限
|
|
|
+ if (!checkPermissionInternal(travelPlan, userId, TravelPlanConstant.Permission.VIEW)) {
|
|
|
+ throw new TravelPlanException("没有权限查看此行程");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分别获取关联数据
|
|
|
+ TravelPlan planWithDetails = travelPlanRepository.findWithDetailListById(planId);
|
|
|
+ TravelPlan planWithCollaborators = travelPlanRepository.findWithCollaboratorsById(planId);
|
|
|
+ TravelPlan planWithOperations = travelPlanRepository.findWithOperationsById(planId);
|
|
|
+
|
|
|
+ // 合并数据
|
|
|
+ travelPlan.setDetails(planWithDetails.getDetails());
|
|
|
+ travelPlan.setCollaborators(planWithCollaborators.getCollaborators());
|
|
|
+ travelPlan.setOperations(planWithOperations.getOperations());
|
|
|
+
|
|
|
+ // 手动映射响应对象
|
|
|
+ TravelPlanResponse response = new TravelPlanResponse();
|
|
|
+ response.setPlanId(travelPlan.getPlanId());
|
|
|
+ response.setUserId(travelPlan.getUserId());
|
|
|
+ response.setPlanName(travelPlan.getPlanName());
|
|
|
+ response.setTotalDays(travelPlan.getTotalDays());
|
|
|
+ response.setTotalBudget(travelPlan.getTotalBudget());
|
|
|
+ response.setPreference(travelPlan.getPreference());
|
|
|
+ response.setStatus(travelPlan.getStatus());
|
|
|
+ response.setCreateTime(travelPlan.getCreateTime());
|
|
|
+ response.setUpdateTime(travelPlan.getUpdateTime());
|
|
|
+
|
|
|
+ // 手动映射详情列表
|
|
|
+ if (travelPlan.getDetails() != null && !travelPlan.getDetails().isEmpty()) {
|
|
|
+ Set<TravelPlanDetailResponse> detailResponses = new HashSet<>();
|
|
|
+ for (TravelPlanDetail detail : travelPlan.getDetails()) {
|
|
|
+ TravelPlanDetailResponse detailResponse = new TravelPlanDetailResponse();
|
|
|
+ detailResponse.setDetailId(detail.getDetailId());
|
|
|
+ detailResponse.setDaySeq(detail.getDaySeq());
|
|
|
+ detailResponse.setSpotId(detail.getSpotId());
|
|
|
+ detailResponse.setSpotName(detail.getSpotName());
|
|
|
+ detailResponse.setStartTime(detail.getStartTime());
|
|
|
+ detailResponse.setEndTime(detail.getEndTime());
|
|
|
+ detailResponse.setTrafficWay(detail.getTrafficWay());
|
|
|
+ detailResponse.setTrafficDesc(detail.getTrafficDesc());
|
|
|
+ detailResponse.setRemark(detail.getRemark());
|
|
|
+ detailResponses.add(detailResponse);
|
|
|
+ }
|
|
|
+ response.setDetails(detailResponses);
|
|
|
+ }
|
|
|
+
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户的行程列表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(readOnly = true)
|
|
|
+ public List<TravelPlanResponse> getUserTravelPlans(String userId) {
|
|
|
+ // 查询用户的行程列表
|
|
|
+ List<TravelPlan> travelPlans = travelPlanRepository.findByUserId(userId);
|
|
|
+
|
|
|
+ // 转换为响应DTO列表
|
|
|
+ return convertToResponseList(travelPlans);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户参与协作的行程列表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(readOnly = true)
|
|
|
+ public List<TravelPlanResponse> getUserCollaboratedPlans(String userId) {
|
|
|
+ // 查询用户参与协作的行程列表
|
|
|
+ List<TravelPlan> travelPlans = travelPlanRepository.findCollaboratedPlans(userId);
|
|
|
+
|
|
|
+ // 转换为响应DTO列表
|
|
|
+ return convertToResponseList(travelPlans);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加行程详情
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public void addTravelPlanDetail(AddTravelPlanDetailRequest request) {
|
|
|
+ // 获取行程
|
|
|
+ TravelPlan travelPlan = getTravelPlanById(request.getPlanId());
|
|
|
+
|
|
|
+ // 检查权限
|
|
|
+ checkPermissionInternal(travelPlan, request.getUserId(), TravelPlanConstant.Permission.EDIT);
|
|
|
+
|
|
|
+ // 创建行程详情实体
|
|
|
+ TravelPlanDetail detail = new TravelPlanDetail();
|
|
|
+ detail.setTravelPlan(travelPlan);
|
|
|
+ detail.setDaySeq(request.getDaySeq());
|
|
|
+ detail.setSpotId(request.getSpotId());
|
|
|
+ detail.setSpotName(request.getSpotName());
|
|
|
+ detail.setStartTime(request.getStartTime());
|
|
|
+ detail.setEndTime(request.getEndTime());
|
|
|
+ detail.setTrafficWay(request.getTrafficWay());
|
|
|
+ detail.setTrafficDesc(request.getTrafficDesc());
|
|
|
+ detail.setRemark(request.getRemark());
|
|
|
+
|
|
|
+ // 保存行程详情
|
|
|
+ detailRepository.save(detail);
|
|
|
+
|
|
|
+ // 更新行程更新时间
|
|
|
+ travelPlan.setUpdateTime(new Date());
|
|
|
+ travelPlanRepository.save(travelPlan);
|
|
|
+
|
|
|
+ // 记录操作
|
|
|
+ recordOperationInternal(travelPlan.getPlanId(), TravelPlanConstant.OperationType.SAVE,
|
|
|
+ request.getUserId(), "添加行程详情");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除行程详情
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public void deleteTravelPlanDetail(Long detailId, String userId) {
|
|
|
+ // 获取行程详情
|
|
|
+ TravelPlanDetail detail = detailRepository.findById(detailId)
|
|
|
+ .orElseThrow(() -> new TravelPlanException("行程详情不存在"));
|
|
|
+
|
|
|
+ // 获取关联的行程
|
|
|
+ TravelPlan travelPlan = detail.getTravelPlan();
|
|
|
+
|
|
|
+ // 检查权限
|
|
|
+ checkPermissionInternal(travelPlan, userId, TravelPlanConstant.Permission.EDIT);
|
|
|
+
|
|
|
+ // 删除行程详情
|
|
|
+ detailRepository.deleteById(detailId);
|
|
|
+
|
|
|
+ // 更新行程更新时间
|
|
|
+ travelPlan.setUpdateTime(new Date());
|
|
|
+ travelPlanRepository.save(travelPlan);
|
|
|
+
|
|
|
+ // 记录操作
|
|
|
+ recordOperationInternal(travelPlan.getPlanId(), TravelPlanConstant.OperationType.SAVE,
|
|
|
+ userId, "删除行程详情");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加协作人
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public void addCollaborator(AddCollaboratorRequest request) {
|
|
|
+ // 获取行程
|
|
|
+ TravelPlan travelPlan = getTravelPlanById(request.getPlanId());
|
|
|
+
|
|
|
+ // 检查权限(只有管理员或创建者可以添加协作人)
|
|
|
+ if (!travelPlan.getUserId().equals(request.getOperatorUserId()) &&
|
|
|
+ !checkPermissionInternal(travelPlan, request.getOperatorUserId(), TravelPlanConstant.Permission.ADMIN)) {
|
|
|
+ throw new TravelPlanException("没有权限添加协作人");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查协作人是否已存在
|
|
|
+ TravelPlanCollaborator existingCollaborator = collaboratorRepository
|
|
|
+ .findByTravelPlanPlanIdAndCollabUserId(request.getPlanId(), request.getCollabUserId());
|
|
|
+
|
|
|
+ if (existingCollaborator != null) {
|
|
|
+ // 更新现有协作人的权限
|
|
|
+ existingCollaborator.setPermission(request.getPermission());
|
|
|
+ collaboratorRepository.save(existingCollaborator);
|
|
|
+ } else {
|
|
|
+ // 创建新的协作人关系
|
|
|
+ TravelPlanCollaborator collaborator = new TravelPlanCollaborator();
|
|
|
+ collaborator.setTravelPlan(travelPlan);
|
|
|
+ collaborator.setCollabUserId(request.getCollabUserId());
|
|
|
+ collaborator.setPermission(request.getPermission());
|
|
|
+ collaborator.setJoinTime(new Date());
|
|
|
+
|
|
|
+ // 保存协作人关系
|
|
|
+ collaboratorRepository.save(collaborator);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 记录操作
|
|
|
+ recordOperationInternal(travelPlan.getPlanId(), TravelPlanConstant.OperationType.OTHER,
|
|
|
+ request.getOperatorUserId(), "添加协作人");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除协作人
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public void removeCollaborator(Long planId, String collabUserId, String operatorUserId) {
|
|
|
+ // 获取行程
|
|
|
+ TravelPlan travelPlan = getTravelPlanById(planId);
|
|
|
+
|
|
|
+ // 检查权限(只有管理员或创建者可以删除协作人)
|
|
|
+ if (!travelPlan.getUserId().equals(operatorUserId) &&
|
|
|
+ !checkPermissionInternal(travelPlan, operatorUserId, TravelPlanConstant.Permission.ADMIN)) {
|
|
|
+ throw new TravelPlanException("没有权限删除协作人");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 删除协作人关系
|
|
|
+ TravelPlanCollaborator collaborator = collaboratorRepository
|
|
|
+ .findByTravelPlanPlanIdAndCollabUserId(planId, collabUserId);
|
|
|
+
|
|
|
+ if (collaborator != null) {
|
|
|
+ collaboratorRepository.delete(collaborator);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 记录操作
|
|
|
+ recordOperationInternal(planId, TravelPlanConstant.OperationType.OTHER,
|
|
|
+ operatorUserId, "删除协作人");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 记录行程操作
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional
|
|
|
+ public void recordOperation(RecordOperationRequest request) {
|
|
|
+ // 获取行程
|
|
|
+ TravelPlan travelPlan = getTravelPlanById(request.getPlanId());
|
|
|
+
|
|
|
+ // 检查权限
|
|
|
+ checkPermissionInternal(travelPlan, request.getOpUserId(), TravelPlanConstant.Permission.VIEW);
|
|
|
+
|
|
|
+ // 记录操作
|
|
|
+ recordOperationInternal(request.getPlanId(), request.getOpType(),
|
|
|
+ request.getOpUserId(), request.getOpDesc());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查用户是否有访问行程的权限
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public boolean checkPermission(Long planId, String userId, int requiredPermission) {
|
|
|
+ // 获取行程
|
|
|
+ TravelPlan travelPlan = getTravelPlanById(planId);
|
|
|
+
|
|
|
+ // 检查权限
|
|
|
+ return checkPermissionInternal(travelPlan, userId, requiredPermission);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 内部方法:根据ID获取行程
|
|
|
+ */
|
|
|
+ private TravelPlan getTravelPlanById(Long planId) {
|
|
|
+ return travelPlanRepository.findById(planId)
|
|
|
+ .orElseThrow(() -> new TravelPlanException("行程不存在"));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 内部方法:检查用户权限
|
|
|
+ */
|
|
|
+ private boolean checkPermissionInternal(TravelPlan travelPlan, String userId, int requiredPermission) {
|
|
|
+ // 如果是行程创建者,拥有所有权限
|
|
|
+ if (travelPlan.getUserId().equals(userId)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查找协作人关系
|
|
|
+ TravelPlanCollaborator collaborator = collaboratorRepository
|
|
|
+ .findByTravelPlanPlanIdAndCollabUserId(travelPlan.getPlanId(), userId);
|
|
|
+
|
|
|
+ // 如果不是协作人,没有权限
|
|
|
+ if (collaborator == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查权限级别
|
|
|
+ return collaborator.getPermission() >= requiredPermission;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 内部方法:记录操作
|
|
|
+ */
|
|
|
+ private void recordOperationInternal(Long planId, int opType, String opUserId, String opDesc) {
|
|
|
+ TravelPlanOperation operation = new TravelPlanOperation();
|
|
|
+ operation.setTravelPlan(travelPlanRepository.getOne(planId));
|
|
|
+ operation.setOpType(opType);
|
|
|
+ operation.setOpUserId(opUserId);
|
|
|
+ operation.setOpTime(new Date());
|
|
|
+ operation.setOpDesc(opDesc);
|
|
|
+
|
|
|
+ operationRepository.save(operation);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 内部方法:将行程列表转换为响应DTO列表
|
|
|
+ */
|
|
|
+ private List<TravelPlanResponse> convertToResponseList(List<TravelPlan> travelPlans) {
|
|
|
+ List<TravelPlanResponse> responses = new ArrayList<>();
|
|
|
+
|
|
|
+ for (TravelPlan plan : travelPlans) {
|
|
|
+ // 手动映射属性,避免懒加载问题
|
|
|
+ TravelPlanResponse response = new TravelPlanResponse();
|
|
|
+ response.setPlanId(plan.getPlanId());
|
|
|
+ response.setUserId(plan.getUserId());
|
|
|
+ response.setPlanName(plan.getPlanName());
|
|
|
+ response.setTotalDays(plan.getTotalDays());
|
|
|
+ response.setTotalBudget(plan.getTotalBudget());
|
|
|
+ response.setPreference(plan.getPreference());
|
|
|
+ response.setStatus(plan.getStatus());
|
|
|
+ response.setCreateTime(plan.getCreateTime());
|
|
|
+ response.setUpdateTime(plan.getUpdateTime());
|
|
|
+
|
|
|
+ responses.add(response);
|
|
|
+ }
|
|
|
+
|
|
|
+ return responses;
|
|
|
+ }
|
|
|
+}
|