package com.tourguide.modules.user.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.tourguide.common.api.PageResponse; import com.tourguide.common.exception.BusinessException; import com.tourguide.common.validation.ChineseIdCardValidator; import com.tourguide.modules.order.dto.VisitorOrderStatRow; import com.tourguide.modules.order.mapper.TourOrderMapper; import com.tourguide.modules.review.dto.VisitorReviewStatRow; import com.tourguide.modules.review.mapper.OrderReviewMapper; import com.tourguide.modules.user.dto.MiniProfileUpdateRequest; import com.tourguide.modules.user.dto.MiniRealNameUpdateRequest; import com.tourguide.modules.user.dto.MiniUserDetailResponse; import com.tourguide.modules.user.dto.MiniUserResponse; import com.tourguide.modules.user.entity.MiniUser; import com.tourguide.modules.user.mapper.MiniUserMapper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.time.LocalDate; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** 仅处理小程序用户,管理后台只能通过本服务执行查询或状态管理。 */ @Service public class MiniUserService { private final MiniUserMapper userMapper; private final TourOrderMapper orderMapper; private final OrderReviewMapper reviewMapper; public MiniUserService(MiniUserMapper userMapper, TourOrderMapper orderMapper, OrderReviewMapper reviewMapper) { this.userMapper = userMapper; this.orderMapper = orderMapper; this.reviewMapper = reviewMapper; } public MiniUser findEnabledById(Long id) { MiniUser user = userMapper.selectById(id); if (user == null || user.getStatus() == null || user.getStatus() != 1) { throw new BusinessException(401, "小程序用户不存在或已停用"); } return user; } public MiniUser findByUsername(String username) { return userMapper.selectOne(new LambdaQueryWrapper().eq(MiniUser::getUsername, username).last("LIMIT 1")); } public PageResponse page(long page, long size, String keyword, Integer status, LocalDate startDate, LocalDate endDate) { LambdaQueryWrapper query = new LambdaQueryWrapper(); if (StringUtils.hasText(keyword)) { String searchKeyword = keyword.trim(); query.and(wrapper -> { wrapper.like(MiniUser::getUsername, searchKeyword) .or().like(MiniUser::getNickname, searchKeyword) .or().like(MiniUser::getMobile, searchKeyword); if (searchKeyword.matches("\\d+")) { wrapper.or().eq(MiniUser::getId, Long.valueOf(searchKeyword)); } }); } query.eq(status != null, MiniUser::getStatus, status) .ge(startDate != null, MiniUser::getCreatedAt, startDate == null ? null : startDate.atStartOfDay()) .lt(endDate != null, MiniUser::getCreatedAt, endDate == null ? null : endDate.plusDays(1).atStartOfDay()) .orderByDesc(MiniUser::getId); Page result = userMapper.selectPage(new Page(page, size), query); List users = result.getRecords(); Map statsByUserId = loadUserStats( users.stream().map(MiniUser::getId).collect(Collectors.toList())); return new PageResponse(users.stream() .map(user -> MiniUserResponse.from(user, statsOf(statsByUserId, user.getId()).orderCount)) .collect(Collectors.toList()), result.getTotal(), result.getCurrent(), result.getSize()); } public MiniUserDetailResponse detail(Long id) { MiniUser user = userMapper.selectById(id); if (user == null) { throw new BusinessException(404, "游客不存在"); } UserStats stats = statsOf(loadUserStats(Collections.singletonList(id)), id); return MiniUserDetailResponse.from(user, stats.orderCount, stats.totalConsumption, stats.reviewCount); } private Map loadUserStats(List visitorIds) { if (visitorIds.isEmpty()) { return Collections.emptyMap(); } Map statsByUserId = new HashMap(); for (Long visitorId : visitorIds) { statsByUserId.put(visitorId, new UserStats()); } List orderRows = orderMapper.selectVisitorOrderStats(visitorIds); if (orderRows != null) { for (VisitorOrderStatRow row : orderRows) { if (row.getVisitorId() == null) { continue; } UserStats stats = statsByUserId.computeIfAbsent(row.getVisitorId(), ignored -> new UserStats()); stats.orderCount = defaultLong(row.getOrderCount()); stats.totalConsumption = row.getTotalConsumption() == null ? BigDecimal.ZERO : row.getTotalConsumption(); } } List reviewRows = reviewMapper.selectVisitorReviewStats(visitorIds); if (reviewRows != null) { for (VisitorReviewStatRow row : reviewRows) { if (row.getVisitorId() == null) { continue; } statsByUserId.computeIfAbsent(row.getVisitorId(), ignored -> new UserStats()) .reviewCount = defaultLong(row.getReviewCount()); } } return statsByUserId; } private static UserStats statsOf(Map statsByUserId, Long userId) { UserStats stats = statsByUserId.get(userId); return stats == null ? new UserStats() : stats; } private static long defaultLong(Long value) { return value == null ? 0L : value; } @Transactional public MiniUserResponse updateProfile(Long id, MiniProfileUpdateRequest request) { MiniUser user = findEnabledById(id); user.setNickname(request.getNickname().trim()); userMapper.updateById(user); return MiniUserResponse.from(user); } @Transactional public MiniUserResponse updateAvatar(Long id, String avatar) { MiniUser user = findEnabledById(id); user.setAvatar(avatar); userMapper.updateById(user); return MiniUserResponse.from(user); } @Transactional public MiniUserResponse updateRealName(Long id, MiniRealNameUpdateRequest request) { MiniUser user = findEnabledById(id); String idCardNo = request.getIdCardNo().trim().toUpperCase(); if (!ChineseIdCardValidator.isValid(idCardNo)) { throw new BusinessException(400, "身份证号格式不正确"); } if (userMapper.selectCount(new LambdaQueryWrapper() .eq(MiniUser::getIdCardNo, idCardNo) .ne(MiniUser::getId, id)) > 0) { throw new BusinessException(409, "该身份证号已被其他账号使用"); } user.setRealName(request.getRealName().trim()); user.setIdCardNo(idCardNo); userMapper.updateById(user); return MiniUserResponse.from(user); } @Transactional public void updateStatus(Long id, Integer status) { MiniUser user = userMapper.selectById(id); if (user == null) { throw new BusinessException(404, "小程序用户不存在"); } user.setStatus(status); userMapper.updateById(user); } private static final class UserStats { private long orderCount; private BigDecimal totalConsumption = BigDecimal.ZERO; private long reviewCount; } }